diff options
492 files changed, 11817 insertions, 6424 deletions
diff --git a/Android.bp b/Android.bp index 0780f88df7c6..e756b3428164 100644 --- a/Android.bp +++ b/Android.bp @@ -1415,3 +1415,30 @@ filegroup { name: "framework-telephony-jarjar-rules", srcs: ["telephony/framework-telephony-jarjar-rules.txt"], } + +// protolog start +filegroup { + name: "protolog-common-src", + srcs: [ + "core/java/com/android/internal/protolog/common/**/*.java", + ], +} + +java_library { + name: "protolog-lib", + platform_apis: true, + srcs: [ + "core/java/com/android/internal/protolog/ProtoLogImpl.java", + "core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java", + ":protolog-common-src", + ], +} + +java_library { + name: "protolog-groups", + srcs: [ + "core/java/com/android/internal/protolog/ProtoLogGroup.java", + ":protolog-common-src", + ], +} +// protolog end diff --git a/StubLibraries.bp b/StubLibraries.bp index 0fe34fb650eb..2bd5aee0cd24 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -311,15 +311,6 @@ java_defaults { compile_dex: true, } -java_defaults { - name: "android_stubs_dists_default", - dist: { - targets: ["sdk", "win_sdk"], - tag: ".jar", - dest: "android.jar", - }, -} - java_library_static { name: "android_monolith_stubs_current", srcs: [ ":api-stubs-docs" ], @@ -355,21 +346,7 @@ java_library_static { name: "android_system_monolith_stubs_current", srcs: [ ":system-api-stubs-docs" ], static_libs: [ "private-stub-annotations-jar" ], - defaults: [ - "android_defaults_stubs_current", - "android_stubs_dists_default", - ], - dist: { - dir: "apistubs/android/system", - }, - dists: [ - { - // Legacy dist path - targets: ["sdk", "win_sdk"], - tag: ".jar", - dest: "android_system.jar", - }, - ], + defaults: ["android_defaults_stubs_current"], } java_library_static { @@ -401,34 +378,14 @@ java_library_static { name: "android_test_stubs_current", srcs: [ ":test-api-stubs-docs" ], static_libs: [ "private-stub-annotations-jar" ], - defaults: [ - "android_defaults_stubs_current", - "android_stubs_dists_default", - ], - dist: { - dir: "apistubs/android/test", - }, - dists: [ - { - // Legacy dist path - targets: ["sdk", "win_sdk"], - tag: ".jar", - dest: "android_test.jar", - }, - ], + defaults: ["android_defaults_stubs_current"], } java_library_static { name: "android_module_lib_stubs_current", srcs: [ ":module-lib-api-stubs-docs-non-updatable" ], - defaults: [ - "android_defaults_stubs_current", - "android_stubs_dists_default", - ], + defaults: ["android_defaults_stubs_current"], libs: ["sdk_system_29_android"], - dist: { - dir: "apistubs/android/module-lib", - }, } java_library_static { diff --git a/apct-tests/perftests/contentcapture/Android.bp b/apct-tests/perftests/contentcapture/Android.bp index 66d7348008ab..19a66ad9f27b 100644 --- a/apct-tests/perftests/contentcapture/Android.bp +++ b/apct-tests/perftests/contentcapture/Android.bp @@ -20,9 +20,10 @@ android_test { "androidx.test.rules", "androidx.annotation_annotation", "apct-perftests-utils", - "collector-device-lib-platform", + "collector-device-lib", "compatibility-device-util-axt", ], platform_apis: true, test_suites: ["device-tests"], + data: [":perfetto_artifacts"], } diff --git a/apct-tests/perftests/contentcapture/AndroidManifest.xml b/apct-tests/perftests/contentcapture/AndroidManifest.xml index ee5577f265fa..80957c78abf3 100644 --- a/apct-tests/perftests/contentcapture/AndroidManifest.xml +++ b/apct-tests/perftests/contentcapture/AndroidManifest.xml @@ -16,11 +16,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.perftests.contentcapture"> - <uses-sdk android:targetSdkVersion="28" /> - - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - <uses-permission android:name="android.permission.REAL_GET_TASKS" /> - <application> <uses-library android:name="android.test.runner" /> <activity android:name="android.view.contentcapture.CustomTestActivity" diff --git a/apct-tests/perftests/contentcapture/AndroidTest.xml b/apct-tests/perftests/contentcapture/AndroidTest.xml index d2386bb1efea..d8e0a17d3935 100644 --- a/apct-tests/perftests/contentcapture/AndroidTest.xml +++ b/apct-tests/perftests/contentcapture/AndroidTest.xml @@ -21,7 +21,39 @@ <option name="test-file-name" value="ContentCapturePerfTests.apk" /> </target_preparer> + <!-- Needed for pushing the trace config file --> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" /> + </target_preparer> + + <!-- Needed for pulling the collected trace config on to the host --> + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="pull-pattern-keys" value="perfetto_file_path" /> + </metrics_collector> + + <!-- Needed for storing the perfetto trace files in the sdcard/test_results--> + <option name="isolated-storage" value="false" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.perftests.contentcapture" /> + + <!-- Listener related args for collecting the traces and waiting for the device to stabilize. --> + <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" /> + <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. --> + <option name="instrumentation-arg" key="newRunListenerMode" value="true" /> + + <!-- ProcLoadListener related arguments --> + <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run --> + <option name="instrumentation-arg" key="procload-collector:per_run" value="true" /> + <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" /> + <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" /> + <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" /> + + <!-- PerfettoListener related arguments --> + <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" /> + <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" /> + + <option name="instrumentation-arg" key="newRunListenerMode" value="true" /> </test> </configuration> diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java index c276ae1fe45e..6e644ffb8b27 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java +++ b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java @@ -168,7 +168,9 @@ public final class SearchSpec { /** Sets the maximum number of results to retrieve from the query */ @NonNull public SearchSpec.Builder setNumToRetrieve(int numToRetrieve) { - mResultSpecBuilder.setNumToRetrieve(numToRetrieve); + // Just retrieve everything in one page. + // TODO(b/152359656): Realign these two apis properly. + mResultSpecBuilder.setNumPerPage(numToRetrieve); return this; } diff --git a/api/current.txt b/api/current.txt index b70103b931d4..8cb5b0d68a19 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5596,6 +5596,7 @@ package android.app { method public android.graphics.drawable.Icon getIcon(); method public android.app.RemoteInput[] getRemoteInputs(); method public int getSemanticAction(); + method public boolean isAuthenticationRequired(); method public boolean isContextual(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR; @@ -5625,6 +5626,7 @@ package android.app { method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); method @NonNull public android.os.Bundle getExtras(); method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); + method @NonNull public android.app.Notification.Action.Builder setAuthenticationRequired(boolean); method @NonNull public android.app.Notification.Action.Builder setContextual(boolean); method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int); } @@ -24065,6 +24067,8 @@ package android.media { method public boolean isSink(); method public boolean isSource(); field public static final int TYPE_AUX_LINE = 19; // 0x13 + field public static final int TYPE_BLE_HEADSET = 26; // 0x1a + field public static final int TYPE_BLE_SPEAKER = 27; // 0x1b field public static final int TYPE_BLUETOOTH_A2DP = 8; // 0x8 field public static final int TYPE_BLUETOOTH_SCO = 7; // 0x7 field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1 @@ -65720,7 +65724,7 @@ package java.lang.reflect { package java.math { - public class BigDecimal extends java.lang.Number implements java.lang.Comparable<java.math.BigDecimal> java.io.Serializable { + public class BigDecimal extends java.lang.Number implements java.lang.Comparable<java.math.BigDecimal> { ctor public BigDecimal(char[], int, int); ctor public BigDecimal(char[], int, int, java.math.MathContext); ctor public BigDecimal(char[]); @@ -65807,19 +65811,20 @@ package java.math { field public static final java.math.BigDecimal ZERO; } - public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> java.io.Serializable { + public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> { + ctor public BigInteger(byte[]); + ctor public BigInteger(int, byte[]); + ctor public BigInteger(@NonNull String, int); + ctor public BigInteger(@NonNull String); ctor public BigInteger(int, @NonNull java.util.Random); ctor public BigInteger(int, int, @NonNull java.util.Random); - ctor public BigInteger(@NonNull String); - ctor public BigInteger(@NonNull String, int); - ctor public BigInteger(int, byte[]); - ctor public BigInteger(byte[]); method @NonNull public java.math.BigInteger abs(); method @NonNull public java.math.BigInteger add(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger and(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger andNot(@NonNull java.math.BigInteger); method public int bitCount(); method public int bitLength(); + method public byte byteValueExact(); method @NonNull public java.math.BigInteger clearBit(int); method public int compareTo(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger divide(@NonNull java.math.BigInteger); @@ -65830,8 +65835,10 @@ package java.math { method @NonNull public java.math.BigInteger gcd(@NonNull java.math.BigInteger); method public int getLowestSetBit(); method public int intValue(); + method public int intValueExact(); method public boolean isProbablePrime(int); method public long longValue(); + method public long longValueExact(); method @NonNull public java.math.BigInteger max(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger min(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger mod(@NonNull java.math.BigInteger); @@ -65848,6 +65855,7 @@ package java.math { method @NonNull public java.math.BigInteger setBit(int); method @NonNull public java.math.BigInteger shiftLeft(int); method @NonNull public java.math.BigInteger shiftRight(int); + method public short shortValueExact(); method public int signum(); method @NonNull public java.math.BigInteger subtract(@NonNull java.math.BigInteger); method public boolean testBit(int); diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index f53ac8c895ce..b587ea1f3b74 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -94,6 +94,7 @@ package android.os { } public interface Parcelable { + method public default int getStability(); field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0 field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1 } diff --git a/api/system-current.txt b/api/system-current.txt index 1315a336213d..ea16238316ac 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -301,6 +301,7 @@ package android { field public static final int config_helpIntentNameKey = 17039390; // 0x104001e field public static final int config_helpPackageNameKey = 17039387; // 0x104001b field public static final int config_helpPackageNameValue = 17039388; // 0x104001c + field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028 field public static final int config_systemGallery = 17039399; // 0x1040027 } @@ -7149,6 +7150,8 @@ package android.net.wifi { field @Deprecated public static final int METERED_OVERRIDE_METERED = 1; // 0x1 field @Deprecated public static final int METERED_OVERRIDE_NONE = 0; // 0x0 field @Deprecated public static final int METERED_OVERRIDE_NOT_METERED = 2; // 0x2 + field @Deprecated public static final int RANDOMIZATION_AUTO = 3; // 0x3 + field @Deprecated public static final int RANDOMIZATION_ENHANCED = 2; // 0x2 field @Deprecated public static final int RANDOMIZATION_NONE = 0; // 0x0 field @Deprecated public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1 field @Deprecated public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11 diff --git a/api/test-current.txt b/api/test-current.txt index 0ebbcd7fb3be..10a367fa9267 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -42,6 +42,7 @@ package android { public static final class R.string { field public static final int config_defaultAssistant = 17039393; // 0x1040021 field public static final int config_defaultDialer = 17039395; // 0x1040023 + field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028 field public static final int config_systemGallery = 17039399; // 0x1040027 } diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index a6c402ccc075..15e22a3410cf 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -166,7 +166,7 @@ Status Idmap2Service::verifyIdmap(const std::string& target_apk_path, Status Idmap2Service::createIdmap(const std::string& target_apk_path, const std::string& overlay_apk_path, int32_t fulfilled_policies, bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED, - aidl::nullable<std::string>* _aidl_return) { + std::optional<std::string>* _aidl_return) { assert(_aidl_return); SYSTRACE << "Idmap2Service::createIdmap " << target_apk_path << " " << overlay_apk_path; _aidl_return->reset(); @@ -214,7 +214,7 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path, return error("failed to write to idmap path " + idmap_path); } - *_aidl_return = aidl::make_nullable<std::string>(idmap_path); + *_aidl_return = idmap_path; return ok(); } diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h index ea931c936b0e..1a445192aff8 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.h +++ b/cmds/idmap2/idmap2d/Idmap2Service.h @@ -21,7 +21,6 @@ #include <android-base/unique_fd.h> #include <binder/BinderService.h> -#include <binder/Nullable.h> #include "android/os/BnIdmap2.h" @@ -47,7 +46,7 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 { binder::Status createIdmap(const std::string& target_apk_path, const std::string& overlay_apk_path, int32_t fulfilled_policies, bool enforce_overlayable, int32_t user_id, - aidl::nullable<std::string>* _aidl_return) override; + std::optional<std::string>* _aidl_return) override; private: // Cache the crc of the android framework package since the crc cannot change without a reboot. diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 1579715727ac..7c419519a558 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -85,8 +85,9 @@ cc_defaults { "src/metrics/EventMetricProducer.cpp", "src/metrics/GaugeMetricProducer.cpp", "src/metrics/MetricProducer.cpp", - "src/metrics/metrics_manager_util.cpp", "src/metrics/MetricsManager.cpp", + "src/metrics/parsing_utils/config_update_utils.cpp", + "src/metrics/parsing_utils/metrics_manager_util.cpp", "src/metrics/ValueMetricProducer.cpp", "src/packages/UidMap.cpp", "src/shell/shell_config.proto", @@ -322,6 +323,8 @@ cc_test { "tests/metrics/metrics_test_helper.cpp", "tests/metrics/OringDurationTracker_test.cpp", "tests/metrics/ValueMetricProducer_test.cpp", + "tests/metrics/parsing_utils/config_update_utils_test.cpp", + "tests/metrics/parsing_utils/metrics_manager_util_test.cpp", "tests/MetricsManager_test.cpp", "tests/shell/ShellSubscriber_test.cpp", "tests/state/StateTracker_test.cpp", diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index 6327490b0b71..7bee4e2d1a36 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -546,7 +546,8 @@ void StatsLogProcessor::OnConfigUpdatedLocked(const int64_t timestampNs, const C } } else { // Preserve the existing MetricsManager, update necessary components and metadata in place. - configValid = it->second->updateConfig(timestampNs, config); + configValid = it->second->updateConfig(config, mTimeBaseNs, timestampNs, + mAnomalyAlarmMonitor, mPeriodicAlarmMonitor); if (configValid) { // TODO(b/162323476): refresh TTL, ensure init() is handled properly. mUidMap->OnConfigUpdated(key); diff --git a/cmds/statsd/src/hash.h b/cmds/statsd/src/hash.h index cfe869f60202..bd6b0cd47eaf 100644 --- a/cmds/statsd/src/hash.h +++ b/cmds/statsd/src/hash.h @@ -22,6 +22,7 @@ namespace android { namespace os { namespace statsd { +// Uses murmur2 hashing algorithm. extern uint32_t Hash32(const char *data, size_t n, uint32_t seed); extern uint64_t Hash64(const char* data, size_t n, uint64_t seed); diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp index b94a9572113e..60bcc26f0873 100644 --- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp +++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp @@ -27,8 +27,9 @@ using std::set; using std::unordered_map; using std::vector; -CombinationLogMatchingTracker::CombinationLogMatchingTracker(const int64_t& id, const int index) - : LogMatchingTracker(id, index) { +CombinationLogMatchingTracker::CombinationLogMatchingTracker(const int64_t& id, const int index, + const uint64_t protoHash) + : LogMatchingTracker(id, index, protoHash) { } CombinationLogMatchingTracker::~CombinationLogMatchingTracker() { diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h index 55bc46059fc1..6b8a7fb19cf0 100644 --- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h +++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h @@ -28,7 +28,7 @@ namespace statsd { // Represents a AtomMatcher_Combination in the StatsdConfig. class CombinationLogMatchingTracker : public virtual LogMatchingTracker { public: - CombinationLogMatchingTracker(const int64_t& id, const int index); + CombinationLogMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash); bool init(const std::vector<AtomMatcher>& allLogMatchers, const std::vector<sp<LogMatchingTracker>>& allTrackers, diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h index 88ab4e6f683a..49a41add4560 100644 --- a/cmds/statsd/src/matchers/LogMatchingTracker.h +++ b/cmds/statsd/src/matchers/LogMatchingTracker.h @@ -33,8 +33,8 @@ namespace statsd { class LogMatchingTracker : public virtual RefBase { public: - LogMatchingTracker(const int64_t& id, const int index) - : mId(id), mIndex(index), mInitialized(false){}; + LogMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash) + : mId(id), mIndex(index), mInitialized(false), mProtoHash(protoHash){}; virtual ~LogMatchingTracker(){}; @@ -69,10 +69,14 @@ public: return mAtomIds; } - const int64_t& getId() const { + int64_t getId() const { return mId; } + uint64_t getProtoHash() const { + return mProtoHash; + } + protected: // Name of this matching. We don't really need the name, but it makes log message easy to debug. const int64_t mId; @@ -87,6 +91,14 @@ protected: // return kNotMatched when we receive an event with an id not in the list. This is especially // useful when we have a complex CombinationLogMatcherTracker. std::set<int> mAtomIds; + + // Hash of the AtomMatcher's proto bytes from StatsdConfig. + // Used to determine if the definition of this matcher has changed across a config update. + const uint64_t mProtoHash; + + FRIEND_TEST(MetricsManagerTest, TestCreateLogTrackerSimple); + FRIEND_TEST(MetricsManagerTest, TestCreateLogTrackerCombination); + FRIEND_TEST(ConfigUpdateTest, TestUpdateMatchers); }; } // namespace statsd diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp index 082daf5a1916..ff47d35b36cc 100644 --- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp +++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp @@ -26,11 +26,11 @@ namespace statsd { using std::unordered_map; using std::vector; - SimpleLogMatchingTracker::SimpleLogMatchingTracker(const int64_t& id, const int index, + const uint64_t protoHash, const SimpleAtomMatcher& matcher, - const UidMap& uidMap) - : LogMatchingTracker(id, index), mMatcher(matcher), mUidMap(uidMap) { + const sp<UidMap>& uidMap) + : LogMatchingTracker(id, index, protoHash), mMatcher(matcher), mUidMap(uidMap) { if (!matcher.has_atom_id()) { mInitialized = false; } else { diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h index a0f6a888bd44..e58e01252ade 100644 --- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h +++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h @@ -29,9 +29,8 @@ namespace statsd { class SimpleLogMatchingTracker : public virtual LogMatchingTracker { public: - SimpleLogMatchingTracker(const int64_t& id, const int index, - const SimpleAtomMatcher& matcher, - const UidMap& uidMap); + SimpleLogMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash, + const SimpleAtomMatcher& matcher, const sp<UidMap>& uidMap); ~SimpleLogMatchingTracker(); @@ -46,7 +45,7 @@ public: private: const SimpleAtomMatcher mMatcher; - const UidMap& mUidMap; + const sp<UidMap> mUidMap; }; } // namespace statsd diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp index 2b4c6a3cbf1e..e6d91223308d 100644 --- a/cmds/statsd/src/matchers/matcher_util.cpp +++ b/cmds/statsd/src/matchers/matcher_util.cpp @@ -81,14 +81,15 @@ bool combinationMatch(const vector<int>& children, const LogicalOperation& opera return matched; } -bool tryMatchString(const UidMap& uidMap, const FieldValue& fieldValue, const string& str_match) { +bool tryMatchString(const sp<UidMap>& uidMap, const FieldValue& fieldValue, + const string& str_match) { if (isAttributionUidField(fieldValue) || isUidField(fieldValue)) { int uid = fieldValue.mValue.int_value; auto aidIt = UidMap::sAidToUidMapping.find(str_match); if (aidIt != UidMap::sAidToUidMapping.end()) { return ((int)aidIt->second) == uid; } - std::set<string> packageNames = uidMap.getAppNamesFromUid(uid, true /* normalize*/); + std::set<string> packageNames = uidMap->getAppNamesFromUid(uid, true /* normalize*/); return packageNames.find(str_match) != packageNames.end(); } else if (fieldValue.mValue.getType() == STRING) { return fieldValue.mValue.str_value == str_match; @@ -96,7 +97,7 @@ bool tryMatchString(const UidMap& uidMap, const FieldValue& fieldValue, const st return false; } -bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, +bool matchesSimple(const sp<UidMap>& uidMap, const FieldValueMatcher& matcher, const vector<FieldValue>& values, int start, int end, int depth) { if (depth > 2) { ALOGE("Depth > 3 not supported"); @@ -353,7 +354,7 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, } } -bool matchesSimple(const UidMap& uidMap, const SimpleAtomMatcher& simpleMatcher, +bool matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher, const LogEvent& event) { if (event.GetTagId() != simpleMatcher.atom_id()) { return false; diff --git a/cmds/statsd/src/matchers/matcher_util.h b/cmds/statsd/src/matchers/matcher_util.h index 1ab3e87b5fed..130b6068bd19 100644 --- a/cmds/statsd/src/matchers/matcher_util.h +++ b/cmds/statsd/src/matchers/matcher_util.h @@ -36,8 +36,8 @@ enum MatchingState { bool combinationMatch(const std::vector<int>& children, const LogicalOperation& operation, const std::vector<MatchingState>& matcherResults); -bool matchesSimple(const UidMap& uidMap, - const SimpleAtomMatcher& simpleMatcher, const LogEvent& wrapper); +bool matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher, + const LogEvent& wrapper); } // namespace statsd } // namespace os diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 189d8117ae55..2c3deca40fa0 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -26,7 +26,8 @@ #include "guardrail/StatsdStats.h" #include "matchers/CombinationLogMatchingTracker.h" #include "matchers/SimpleLogMatchingTracker.h" -#include "metrics_manager_util.h" +#include "parsing_utils/config_update_utils.h" +#include "parsing_utils/metrics_manager_util.h" #include "state/StateManager.h" #include "stats_log_util.h" #include "stats_util.h" @@ -76,13 +77,14 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, // Init the ttl end timestamp. refreshTtl(timeBaseNs); - mConfigValid = initStatsdConfig( - key, config, *uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchers, mAllConditionTrackers, - mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers, - mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap, - mActivationAtomTrackerToMetricMap, mDeactivationAtomTrackerToMetricMap, - mAlertTrackerMap, mMetricIndexesWithActivation, mNoReportMetricIds); + mConfigValid = + initStatsdConfig(key, config, uidMap, pullerManager, anomalyAlarmMonitor, + periodicAlarmMonitor, timeBaseNs, currentTimeNs, mTagIds, + mAllAtomMatchers, mLogTrackerMap, mAllConditionTrackers, + mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers, + mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap, + mActivationAtomTrackerToMetricMap, mDeactivationAtomTrackerToMetricMap, + mAlertTrackerMap, mMetricIndexesWithActivation, mNoReportMetricIds); mHashStringsInReport = config.hash_strings_in_metric_report(); mVersionStringsInReport = config.version_strings_in_metric_report(); @@ -195,7 +197,19 @@ MetricsManager::~MetricsManager() { VLOG("~MetricsManager()"); } -bool MetricsManager::updateConfig(const int64_t currentTimeNs, const StatsdConfig& config) { +bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t timeBaseNs, + const int64_t currentTimeNs, + const sp<AlarmMonitor>& anomalyAlarmMonitor, + const sp<AlarmMonitor>& periodicAlarmMonitor) { + vector<sp<LogMatchingTracker>> newAtomMatchers; + unordered_map<int64_t, int> newLogTrackerMap; + mTagIds.clear(); + mConfigValid = + updateStatsdConfig(mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, + periodicAlarmMonitor, timeBaseNs, currentTimeNs, mAllAtomMatchers, + mLogTrackerMap, mTagIds, newAtomMatchers, newLogTrackerMap); + mAllAtomMatchers = newAtomMatchers; + mLogTrackerMap = newLogTrackerMap; return mConfigValid; } diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index 042de29e173d..6f9a23362033 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -46,7 +46,9 @@ public: virtual ~MetricsManager(); - bool updateConfig(const int64_t currentTimeNs, const StatsdConfig& config); + bool updateConfig(const StatsdConfig& config, const int64_t timeBaseNs, + const int64_t currentTimeNs, const sp<AlarmMonitor>& anomalyAlarmMonitor, + const sp<AlarmMonitor>& periodicAlarmMonitor); // Return whether the configuration is valid. bool isConfigValid() const; @@ -237,6 +239,12 @@ private: // Hold all periodic alarm trackers. std::vector<sp<AlarmTracker>> mAllPeriodicAlarmTrackers; + // To make updating configs faster, we map the id of a LogMatchingTracker, MetricProducer, and + // ConditionTracker to its index in the corresponding vector. + + // Maps the id of an atom matcher to its index in mAllAtomMatchers. + std::unordered_map<int64_t, int> mLogTrackerMap; + // To make the log processing more efficient, we want to do as much filtering as possible // before we go into individual trackers and conditions to match. diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp new file mode 100644 index 000000000000..562e29124187 --- /dev/null +++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define DEBUG false // STOPSHIP if true + +#include "config_update_utils.h" + +#include "external/StatsPullerManager.h" +#include "hash.h" +#include "metrics_manager_util.h" + +namespace android { +namespace os { +namespace statsd { + +// Recursive function to determine if a matcher needs to be updated. Populates matcherToUpdate. +// Returns whether the function was successful or not. +bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherIdx, + const unordered_map<int64_t, int>& oldLogTrackerMap, + const vector<sp<LogMatchingTracker>>& oldAtomMatchers, + const unordered_map<int64_t, int>& newLogTrackerMap, + vector<UpdateStatus>& matchersToUpdate, + vector<bool>& cycleTracker) { + // Have already examined this matcher. + if (matchersToUpdate[matcherIdx] != UPDATE_UNKNOWN) { + return true; + } + + const AtomMatcher& matcher = config.atom_matcher(matcherIdx); + int64_t id = matcher.id(); + // Check if new matcher. + const auto& oldLogTrackerIt = oldLogTrackerMap.find(id); + if (oldLogTrackerIt == oldLogTrackerMap.end()) { + matchersToUpdate[matcherIdx] = UPDATE_REPLACE; + return true; + } + + // This is an existing matcher. Check if it has changed. + string serializedMatcher; + if (!matcher.SerializeToString(&serializedMatcher)) { + ALOGE("Unable to serialize matcher %lld", (long long)id); + return false; + } + uint64_t newProtoHash = Hash64(serializedMatcher); + if (newProtoHash != oldAtomMatchers[oldLogTrackerIt->second]->getProtoHash()) { + matchersToUpdate[matcherIdx] = UPDATE_REPLACE; + return true; + } + + switch (matcher.contents_case()) { + case AtomMatcher::ContentsCase::kSimpleAtomMatcher: { + matchersToUpdate[matcherIdx] = UPDATE_PRESERVE; + return true; + } + case AtomMatcher::ContentsCase::kCombination: { + // Recurse to check if children have changed. + cycleTracker[matcherIdx] = true; + UpdateStatus status = UPDATE_PRESERVE; + for (const int64_t childMatcherId : matcher.combination().matcher()) { + const auto& childIt = newLogTrackerMap.find(childMatcherId); + if (childIt == newLogTrackerMap.end()) { + ALOGW("Matcher %lld not found in the config", (long long)childMatcherId); + return false; + } + const int childIdx = childIt->second; + if (cycleTracker[childIdx]) { + ALOGE("Cycle detected in matcher config"); + return false; + } + if (!determineMatcherUpdateStatus(config, childIdx, oldLogTrackerMap, + oldAtomMatchers, newLogTrackerMap, + matchersToUpdate, cycleTracker)) { + return false; + } + + if (matchersToUpdate[childIdx] == UPDATE_REPLACE) { + status = UPDATE_REPLACE; + break; + } + } + matchersToUpdate[matcherIdx] = status; + cycleTracker[matcherIdx] = false; + return true; + } + default: { + ALOGE("Matcher \"%lld\" malformed", (long long)id); + return false; + } + } + return true; +} + +bool updateLogTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, + const unordered_map<int64_t, int>& oldLogTrackerMap, + const vector<sp<LogMatchingTracker>>& oldAtomMatchers, set<int>& allTagIds, + unordered_map<int64_t, int>& newLogTrackerMap, + vector<sp<LogMatchingTracker>>& newAtomMatchers) { + const int atomMatcherCount = config.atom_matcher_size(); + + vector<AtomMatcher> matcherProtos; + matcherProtos.reserve(atomMatcherCount); + newAtomMatchers.reserve(atomMatcherCount); + + // Maps matcher id to their position in the config. For fast lookup of dependencies. + for (int i = 0; i < atomMatcherCount; i++) { + const AtomMatcher& matcher = config.atom_matcher(i); + if (newLogTrackerMap.find(matcher.id()) != newLogTrackerMap.end()) { + ALOGE("Duplicate atom matcher found for id %lld", (long long)matcher.id()); + return false; + } + newLogTrackerMap[matcher.id()] = i; + matcherProtos.push_back(matcher); + } + + // For combination matchers, we need to determine if any children need to be updated. + vector<UpdateStatus> matchersToUpdate(atomMatcherCount, UPDATE_UNKNOWN); + vector<bool> cycleTracker(atomMatcherCount, false); + for (int i = 0; i < atomMatcherCount; i++) { + if (!determineMatcherUpdateStatus(config, i, oldLogTrackerMap, oldAtomMatchers, + newLogTrackerMap, matchersToUpdate, cycleTracker)) { + return false; + } + } + + for (int i = 0; i < atomMatcherCount; i++) { + const AtomMatcher& matcher = config.atom_matcher(i); + const int64_t id = matcher.id(); + switch (matchersToUpdate[i]) { + case UPDATE_PRESERVE: { + const auto& oldLogTrackerIt = oldLogTrackerMap.find(id); + if (oldLogTrackerIt == oldLogTrackerMap.end()) { + ALOGE("Could not find AtomMatcher %lld in the previous config, but expected it " + "to be there", + (long long)id); + return false; + } + const int oldIndex = oldLogTrackerIt->second; + newAtomMatchers.push_back(oldAtomMatchers[oldIndex]); + break; + } + case UPDATE_REPLACE: { + sp<LogMatchingTracker> tracker = createLogTracker(matcher, i, uidMap); + if (tracker == nullptr) { + return false; + } + newAtomMatchers.push_back(tracker); + break; + } + default: { + ALOGE("Matcher \"%lld\" update state is unknown. This should never happen", + (long long)id); + return false; + } + } + } + + std::fill(cycleTracker.begin(), cycleTracker.end(), false); + for (auto& matcher : newAtomMatchers) { + if (!matcher->init(matcherProtos, newAtomMatchers, newLogTrackerMap, cycleTracker)) { + return false; + } + // Collect all the tag ids that are interesting. TagIds exist in leaf nodes only. + const set<int>& tagIds = matcher->getAtomIds(); + allTagIds.insert(tagIds.begin(), tagIds.end()); + } + + return true; +} + +bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, + const sp<StatsPullerManager>& pullerManager, + const sp<AlarmMonitor>& anomalyAlarmMonitor, + const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, + const int64_t currentTimeNs, + const vector<sp<LogMatchingTracker>>& oldAtomMatchers, + const unordered_map<int64_t, int>& oldLogTrackerMap, set<int>& allTagIds, + vector<sp<LogMatchingTracker>>& newAtomMatchers, + unordered_map<int64_t, int>& newLogTrackerMap) { + if (!updateLogTrackers(config, uidMap, oldLogTrackerMap, oldAtomMatchers, allTagIds, + newLogTrackerMap, newAtomMatchers)) { + ALOGE("updateLogMatchingTrackers failed"); + return false; + } + + return true; +} + +} // namespace statsd +} // namespace os +} // namespace android
\ No newline at end of file diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h new file mode 100644 index 000000000000..951ab03cee47 --- /dev/null +++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#include <vector> + +#include "anomaly/AlarmMonitor.h" +#include "external/StatsPullerManager.h" +#include "matchers/LogMatchingTracker.h" + +namespace android { +namespace os { +namespace statsd { + +// Helper functions for MetricsManager to update itself from a new StatsdConfig. +// *Note*: only updateStatsdConfig() should be called from outside this file. +// All other functions are intermediate steps, created to make unit testing easier. + +// Possible update states for a component. PRESERVE means we should keep the existing one. +// REPLACE means we should create a new one, either because it didn't exist or it changed. +enum UpdateStatus { + UPDATE_UNKNOWN = 0, + UPDATE_PRESERVE = 1, + UPDATE_REPLACE = 2, +}; + +// Recursive function to determine if a matcher needs to be updated. +// input: +// [config]: the input StatsdConfig +// [matcherIdx]: the index of the current matcher to be updated +// [newLogTrackerMap]: matcher id to index mapping in the input StatsdConfig +// [oldLogTrackerMap]: matcher id to index mapping in the existing MetricsManager +// [oldAtomMatchers]: stores the existing LogMatchingTrackers +// output: +// [matchersToUpdate]: vector of the update status of each matcher. The matcherIdx index will +// be updated from UPDATE_UNKNOWN after this call. +// [cycleTracker]: intermediate param used during recursion. +bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherIdx, + const unordered_map<int64_t, int>& oldLogTrackerMap, + const vector<sp<LogMatchingTracker>>& oldAtomMatchers, + const unordered_map<int64_t, int>& newLogTrackerMap, + vector<UpdateStatus>& matchersToUpdate, + vector<bool>& cycleTracker); + +// Updates the LogMatchingTrackers. +// input: +// [config]: the input StatsdConfig +// [oldLogTrackerMap]: existing matcher id to index mapping +// [oldAtomMatchers]: stores the existing LogMatchingTrackers +// output: +// [allTagIds]: contains the set of all interesting tag ids to this config. +// [newLogTrackerMap]: new matcher id to index mapping +// [newAtomMatchers]: stores the new LogMatchingTrackers +bool updateLogTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, + const unordered_map<int64_t, int>& oldLogTrackerMap, + const vector<sp<LogMatchingTracker>>& oldAtomMatchers, set<int>& allTagIds, + unordered_map<int64_t, int>& newLogTrackerMap, + vector<sp<LogMatchingTracker>>& newAtomMatchers); + +// Updates the existing MetricsManager from a new StatsdConfig. +// Parameters are the members of MetricsManager. See MetricsManager for declaration. +bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, + const sp<StatsPullerManager>& pullerManager, + const sp<AlarmMonitor>& anomalyAlarmMonitor, + const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, + const int64_t currentTimeNs, + const std::vector<sp<LogMatchingTracker>>& oldAtomMatchers, + const unordered_map<int64_t, int>& oldLogTrackerMap, + std::set<int>& allTagIds, + std::vector<sp<LogMatchingTracker>>& newAtomMatchers, + unordered_map<int64_t, int>& newLogTrackerMap); + +} // namespace statsd +} // namespace os +} // namespace android
\ No newline at end of file diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp index 8917c36bb608..9d3943fe8260 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp @@ -22,10 +22,10 @@ #include <inttypes.h> #include "FieldValue.h" -#include "MetricProducer.h" #include "condition/CombinationConditionTracker.h" #include "condition/SimpleConditionTracker.h" #include "external/StatsPullerManager.h" +#include "hash.h" #include "matchers/CombinationLogMatchingTracker.h" #include "matchers/EventMatcherWizard.h" #include "matchers/SimpleLogMatchingTracker.h" @@ -33,6 +33,7 @@ #include "metrics/DurationMetricProducer.h" #include "metrics/EventMetricProducer.h" #include "metrics/GaugeMetricProducer.h" +#include "metrics/MetricProducer.h" #include "metrics/ValueMetricProducer.h" #include "state/StateManager.h" #include "stats_util.h" @@ -61,6 +62,28 @@ bool hasLeafNode(const FieldMatcher& matcher) { } // namespace +sp<LogMatchingTracker> createLogTracker(const AtomMatcher& logMatcher, const int index, + const sp<UidMap>& uidMap) { + string serializedMatcher; + if (!logMatcher.SerializeToString(&serializedMatcher)) { + ALOGE("Unable to serialize matcher %lld", (long long)logMatcher.id()); + return nullptr; + } + uint64_t protoHash = Hash64(serializedMatcher); + switch (logMatcher.contents_case()) { + case AtomMatcher::ContentsCase::kSimpleAtomMatcher: + return new SimpleLogMatchingTracker(logMatcher.id(), index, protoHash, + logMatcher.simple_atom_matcher(), uidMap); + break; + case AtomMatcher::ContentsCase::kCombination: + return new CombinationLogMatchingTracker(logMatcher.id(), index, protoHash); + break; + default: + ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id()); + return nullptr; + } +} + bool handleMetricWithLogTrackers(const int64_t what, const int metricIndex, const bool usedForDimension, const vector<sp<LogMatchingTracker>>& allAtomMatchers, @@ -125,8 +148,6 @@ bool handleMetricWithConditions( ALOGW("cannot find Predicate \"%lld\" in the config", (long long)link.condition()); return false; } - allConditionTrackers[condition_it->second]->setSliced(true); - allConditionTrackers[it->second]->setSliced(true); } conditionIndex = condition_it->second; @@ -184,9 +205,7 @@ bool handleMetricWithStateLink(const FieldMatcher& stateMatcher, // to provide the producer with state about its activators and deactivators. // Returns false if there are errors. bool handleMetricActivation( - const StatsdConfig& config, - const int64_t metricId, - const int metricIndex, + const StatsdConfig& config, const int64_t metricId, const int metricIndex, const unordered_map<int64_t, int>& metricToActivationMap, const unordered_map<int64_t, int>& logTrackerMap, unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap, @@ -210,10 +229,11 @@ bool handleMetricActivation( return false; } - ActivationType activationType = (activation.has_activation_type()) ? - activation.activation_type() : metricActivation.activation_type(); - std::shared_ptr<Activation> activationWrapper = std::make_shared<Activation>( - activationType, activation.ttl_seconds() * NS_PER_SEC); + ActivationType activationType = (activation.has_activation_type()) + ? activation.activation_type() + : metricActivation.activation_type(); + std::shared_ptr<Activation> activationWrapper = + std::make_shared<Activation>(activationType, activation.ttl_seconds() * NS_PER_SEC); int atomMatcherIndex = itr->second; activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(metricIndex); @@ -235,7 +255,7 @@ bool handleMetricActivation( return true; } -bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap, +bool initLogTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, unordered_map<int64_t, int>& logTrackerMap, vector<sp<LogMatchingTracker>>& allAtomMatchers, set<int>& allTagIds) { vector<AtomMatcher> matcherConfigs; @@ -245,22 +265,12 @@ bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap, for (int i = 0; i < atomMatcherCount; i++) { const AtomMatcher& logMatcher = config.atom_matcher(i); - int index = allAtomMatchers.size(); - switch (logMatcher.contents_case()) { - case AtomMatcher::ContentsCase::kSimpleAtomMatcher: - allAtomMatchers.push_back(new SimpleLogMatchingTracker( - logMatcher.id(), index, logMatcher.simple_atom_matcher(), uidMap)); - break; - case AtomMatcher::ContentsCase::kCombination: - allAtomMatchers.push_back( - new CombinationLogMatchingTracker(logMatcher.id(), index)); - break; - default: - ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id()); - return false; - // continue; + sp<LogMatchingTracker> tracker = createLogTracker(logMatcher, index, uidMap); + if (tracker == nullptr) { + return false; } + allAtomMatchers.push_back(tracker); if (logTrackerMap.find(logMatcher.id()) != logTrackerMap.end()) { ALOGE("Duplicate AtomMatcher found!"); return false; @@ -383,7 +393,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t const MetricActivation& metricActivation = config.metric_activation(i); int64_t metricId = metricActivation.metric_id(); if (metricToActivationMap.find(metricId) != metricToActivationMap.end()) { - ALOGE("Metric %lld has multiple MetricActivations", (long long) metricId); + ALOGE("Metric %lld has multiple MetricActivations", (long long)metricId); return false; } metricToActivationMap.insert({metricId, i}); @@ -402,9 +412,8 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t metricMap.insert({metric.id(), metricIndex}); int trackerIndex; if (!handleMetricWithLogTrackers(metric.what(), metricIndex, - metric.has_dimensions_in_what(), - allAtomMatchers, logTrackerMap, trackerToMetricMap, - trackerIndex)) { + metric.has_dimensions_in_what(), allAtomMatchers, + logTrackerMap, trackerToMetricMap, trackerIndex)) { return false; } @@ -438,10 +447,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t unordered_map<int, shared_ptr<Activation>> eventActivationMap; unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; - bool success = handleMetricActivation(config, metric.id(), metricIndex, - metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap, - deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap, - eventDeactivationMap); + bool success = handleMetricActivation( + config, metric.id(), metricIndex, metricToActivationMap, logTrackerMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + metricsWithActivation, eventActivationMap, eventDeactivationMap); if (!success) return false; sp<MetricProducer> countProducer = @@ -544,10 +553,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t unordered_map<int, shared_ptr<Activation>> eventActivationMap; unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; - bool success = handleMetricActivation(config, metric.id(), metricIndex, - metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap, - deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap, - eventDeactivationMap); + bool success = handleMetricActivation( + config, metric.id(), metricIndex, metricToActivationMap, logTrackerMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + metricsWithActivation, eventActivationMap, eventDeactivationMap); if (!success) return false; sp<MetricProducer> durationMetric = new DurationMetricProducer( @@ -591,10 +600,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t unordered_map<int, shared_ptr<Activation>> eventActivationMap; unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; - bool success = handleMetricActivation(config, metric.id(), metricIndex, - metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap, - deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap, - eventDeactivationMap); + bool success = handleMetricActivation( + config, metric.id(), metricIndex, metricToActivationMap, logTrackerMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + metricsWithActivation, eventActivationMap, eventDeactivationMap); if (!success) return false; sp<MetricProducer> eventMetric = @@ -626,9 +635,8 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t metricMap.insert({metric.id(), metricIndex}); int trackerIndex; if (!handleMetricWithLogTrackers(metric.what(), metricIndex, - metric.has_dimensions_in_what(), - allAtomMatchers, logTrackerMap, trackerToMetricMap, - trackerIndex)) { + metric.has_dimensions_in_what(), allAtomMatchers, + logTrackerMap, trackerToMetricMap, trackerIndex)) { return false; } @@ -718,9 +726,8 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t metricMap.insert({metric.id(), metricIndex}); int trackerIndex; if (!handleMetricWithLogTrackers(metric.what(), metricIndex, - metric.has_dimensions_in_what(), - allAtomMatchers, logTrackerMap, trackerToMetricMap, - trackerIndex)) { + metric.has_dimensions_in_what(), allAtomMatchers, + logTrackerMap, trackerToMetricMap, trackerIndex)) { return false; } @@ -775,10 +782,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t unordered_map<int, shared_ptr<Activation>> eventActivationMap; unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap; - bool success = handleMetricActivation(config, metric.id(), metricIndex, - metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap, - deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap, - eventDeactivationMap); + bool success = handleMetricActivation( + config, metric.id(), metricIndex, metricToActivationMap, logTrackerMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + metricsWithActivation, eventActivationMap, eventDeactivationMap); if (!success) return false; sp<MetricProducer> gaugeProducer = new GaugeMetricProducer( @@ -813,8 +820,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t return true; } -bool initAlerts(const StatsdConfig& config, - const unordered_map<int64_t, int>& metricProducerMap, +bool initAlerts(const StatsdConfig& config, const unordered_map<int64_t, int>& metricProducerMap, unordered_map<int64_t, int>& alertTrackerMap, const sp<AlarmMonitor>& anomalyAlarmMonitor, vector<sp<MetricProducer>>& allMetricProducers, @@ -832,8 +838,8 @@ bool initAlerts(const StatsdConfig& config, return false; } if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) { - ALOGW("invalid alert: threshold=%f num_buckets= %d", - alert.trigger_if_sum_gt(), alert.num_buckets()); + ALOGW("invalid alert: threshold=%f num_buckets= %d", alert.trigger_if_sum_gt(), + alert.num_buckets()); return false; } const int metricIndex = itr->second; @@ -853,14 +859,13 @@ bool initAlerts(const StatsdConfig& config, } if (subscription.subscriber_information_case() == Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) { - ALOGW("subscription \"%lld\" has no subscriber info.\"", - (long long)subscription.id()); + ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id()); return false; } const auto& itr = alertTrackerMap.find(subscription.rule_id()); if (itr == alertTrackerMap.end()) { ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"", - (long long)subscription.id(), (long long)subscription.rule_id()); + (long long)subscription.id(), (long long)subscription.rule_id()); return false; } const int anomalyTrackerIndex = itr->second; @@ -870,12 +875,11 @@ bool initAlerts(const StatsdConfig& config, } bool initAlarms(const StatsdConfig& config, const ConfigKey& key, - const sp<AlarmMonitor>& periodicAlarmMonitor, - const int64_t timeBaseNs, const int64_t currentTimeNs, - vector<sp<AlarmTracker>>& allAlarmTrackers) { + const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, + const int64_t currentTimeNs, vector<sp<AlarmTracker>>& allAlarmTrackers) { unordered_map<int64_t, int> alarmTrackerMap; int64_t startMillis = timeBaseNs / 1000 / 1000; - int64_t currentTimeMillis = currentTimeNs / 1000 /1000; + int64_t currentTimeMillis = currentTimeNs / 1000 / 1000; for (int i = 0; i < config.alarm_size(); i++) { const Alarm& alarm = config.alarm(i); if (alarm.offset_millis() <= 0) { @@ -888,8 +892,7 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key, } alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size())); allAlarmTrackers.push_back( - new AlarmTracker(startMillis, currentTimeMillis, - alarm, key, periodicAlarmMonitor)); + new AlarmTracker(startMillis, currentTimeMillis, alarm, key, periodicAlarmMonitor)); } for (int i = 0; i < config.subscription_size(); ++i) { const Subscription& subscription = config.subscription(i); @@ -898,14 +901,13 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key, } if (subscription.subscriber_information_case() == Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) { - ALOGW("subscription \"%lld\" has no subscriber info.\"", - (long long)subscription.id()); + ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id()); return false; } const auto& itr = alarmTrackerMap.find(subscription.rule_id()); if (itr == alarmTrackerMap.end()) { ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"", - (long long)subscription.id(), (long long)subscription.rule_id()); + (long long)subscription.id(), (long long)subscription.rule_id()); return false; } const int trackerIndex = itr->second; @@ -914,12 +916,13 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key, return true; } -bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap, +bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, const sp<StatsPullerManager>& pullerManager, const sp<AlarmMonitor>& anomalyAlarmMonitor, const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, const int64_t currentTimeNs, set<int>& allTagIds, vector<sp<LogMatchingTracker>>& allAtomMatchers, + unordered_map<int64_t, int>& logTrackerMap, vector<sp<ConditionTracker>>& allConditionTrackers, vector<sp<MetricProducer>>& allMetricProducers, vector<sp<AnomalyTracker>>& allAnomalyTrackers, @@ -930,9 +933,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap, unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, unordered_map<int64_t, int>& alertTrackerMap, - vector<int>& metricsWithActivation, - std::set<int64_t>& noReportMetricIds) { - unordered_map<int64_t, int> logTrackerMap; + vector<int>& metricsWithActivation, std::set<int64_t>& noReportMetricIds) { unordered_map<int64_t, int> conditionTrackerMap; vector<ConditionState> initialConditionCache; unordered_map<int64_t, int> metricProducerMap; @@ -969,8 +970,8 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& ALOGE("initAlerts failed"); return false; } - if (!initAlarms(config, key, periodicAlarmMonitor, - timeBaseNs, currentTimeNs, allPeriodicAlarmTrackers)) { + if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs, + allPeriodicAlarmTrackers)) { ALOGE("initAlarms failed"); return false; } diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h index 96b5c26ff789..ed9951fd5ee6 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h @@ -20,16 +20,28 @@ #include <unordered_map> #include <vector> -#include "../anomaly/AlarmTracker.h" -#include "../condition/ConditionTracker.h" -#include "../external/StatsPullerManager.h" -#include "../matchers/LogMatchingTracker.h" -#include "../metrics/MetricProducer.h" +#include "anomaly/AlarmTracker.h" +#include "condition/ConditionTracker.h" +#include "external/StatsPullerManager.h" +#include "matchers/LogMatchingTracker.h" +#include "metrics/MetricProducer.h" namespace android { namespace os { namespace statsd { +// Helper functions for creating individual config components from StatsdConfig. +// Should only be called from metrics_manager_util and config_update_utils. + +// Create a LogMatchingTracker. +// input: +// [logMatcher]: the input AtomMatcher from the StatsdConfig +// [index]: the index of the matcher +// output: +// new LogMatchingTracker, or null if the tracker is unable to be created +sp<LogMatchingTracker> createLogTracker(const AtomMatcher& logMatcher, const int index, + const sp<UidMap>& uidMap); + // Helper functions for MetricsManager to initialize from StatsdConfig. // *Note*: only initStatsdConfig() should be called from outside. // All other functions are intermediate @@ -44,8 +56,7 @@ namespace statsd { // [logTrackerMap]: this map should contain matcher name to index mapping // [allAtomMatchers]: should store the sp to all the LogMatchingTracker // [allTagIds]: contains the set of all interesting tag ids to this config. -bool initLogTrackers(const StatsdConfig& config, - const UidMap& uidMap, +bool initLogTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, std::unordered_map<int64_t, int>& logTrackerMap, std::vector<sp<LogMatchingTracker>>& allAtomMatchers, std::set<int>& allTagIds); @@ -97,7 +108,7 @@ bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAt // [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index. bool initMetrics( const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseTimeNs, - const int64_t currentTimeNs, UidMap& uidMap, const sp<StatsPullerManager>& pullerManager, + const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager, const std::unordered_map<int64_t, int>& logTrackerMap, const std::unordered_map<int64_t, int>& conditionTrackerMap, const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks, @@ -116,12 +127,13 @@ bool initMetrics( // Initialize MetricsManager from StatsdConfig. // Parameters are the members of MetricsManager. See MetricsManager for declaration. -bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap, +bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, const sp<StatsPullerManager>& pullerManager, const sp<AlarmMonitor>& anomalyAlarmMonitor, const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, const int64_t currentTimeNs, std::set<int>& allTagIds, std::vector<sp<LogMatchingTracker>>& allAtomMatchers, + std::unordered_map<int64_t, int>& logTrackerMap, std::vector<sp<ConditionTracker>>& allConditionTrackers, std::vector<sp<MetricProducer>>& allMetricProducers, vector<sp<AnomalyTracker>>& allAnomalyTrackers, @@ -132,8 +144,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap, unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, std::unordered_map<int64_t, int>& alertTrackerMap, - vector<int>& metricsWithActivation, - std::set<int64_t>& noReportMetricIds); + vector<int>& metricsWithActivation, std::set<int64_t>& noReportMetricIds); } // namespace statsd } // namespace os diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp index fd883c29dba0..9d8f0c24e253 100644 --- a/cmds/statsd/src/shell/ShellSubscriber.cpp +++ b/cmds/statsd/src/shell/ShellSubscriber.cpp @@ -191,7 +191,7 @@ void ShellSubscriber::writePulledAtomsLocked(const vector<std::shared_ptr<LogEve mProto.clear(); int count = 0; for (const auto& event : data) { - if (matchesSimple(*mUidMap, matcher, *event)) { + if (matchesSimple(mUidMap, matcher, *event)) { count++; uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE | util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM); @@ -209,7 +209,7 @@ void ShellSubscriber::onLogEvent(const LogEvent& event) { mProto.clear(); for (const auto& matcher : mSubscriptionInfo->mPushedMatchers) { - if (matchesSimple(*mUidMap, matcher, event)) { + if (matchesSimple(mUidMap, matcher, event)) { uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE | util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM); event.ToProto(mProto); diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp index 6264c075426a..92cd04f37ee0 100644 --- a/cmds/statsd/tests/LogEntryMatcher_test.cpp +++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp @@ -110,7 +110,7 @@ void makeBoolLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t ti } // anonymous namespace TEST(AtomMatcherTest, TestSimpleMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; @@ -129,7 +129,7 @@ TEST(AtomMatcherTest, TestSimpleMatcher) { } TEST(AtomMatcherTest, TestAttributionMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); std::vector<int> attributionUids = {1111, 2222, 3333}; std::vector<string> attributionTags = {"location1", "location2", "location3"}; @@ -204,7 +204,7 @@ TEST(AtomMatcherTest, TestAttributionMatcher) { "pkg0"); EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event)); - uidMap.updateMap( + uidMap->updateMap( 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, {android::String16("v1"), android::String16("v1"), android::String16("v2"), android::String16("v1"), android::String16("v2")}, @@ -356,8 +356,8 @@ TEST(AtomMatcherTest, TestAttributionMatcher) { } TEST(AtomMatcherTest, TestUidFieldMatcher) { - UidMap uidMap; - uidMap.updateMap( + sp<UidMap> uidMap = new UidMap(); + uidMap->updateMap( 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, {android::String16("v1"), android::String16("v1"), android::String16("v2"), android::String16("v1"), android::String16("v2")}, @@ -392,8 +392,8 @@ TEST(AtomMatcherTest, TestUidFieldMatcher) { } TEST(AtomMatcherTest, TestNeqAnyStringMatcher) { - UidMap uidMap; - uidMap.updateMap( + sp<UidMap> uidMap = new UidMap(); + uidMap->updateMap( 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, {android::String16("v1"), android::String16("v1"), android::String16("v2"), android::String16("v1"), android::String16("v2")}, @@ -453,8 +453,8 @@ TEST(AtomMatcherTest, TestNeqAnyStringMatcher) { } TEST(AtomMatcherTest, TestEqAnyStringMatcher) { - UidMap uidMap; - uidMap.updateMap( + sp<UidMap> uidMap = new UidMap(); + uidMap->updateMap( 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, {android::String16("v1"), android::String16("v1"), android::String16("v2"), android::String16("v1"), android::String16("v2")}, @@ -517,7 +517,7 @@ TEST(AtomMatcherTest, TestEqAnyStringMatcher) { } TEST(AtomMatcherTest, TestBoolMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; auto simpleMatcher = matcher.mutable_simple_atom_matcher(); @@ -550,7 +550,7 @@ TEST(AtomMatcherTest, TestBoolMatcher) { } TEST(AtomMatcherTest, TestStringMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; auto simpleMatcher = matcher.mutable_simple_atom_matcher(); @@ -568,7 +568,7 @@ TEST(AtomMatcherTest, TestStringMatcher) { } TEST(AtomMatcherTest, TestMultiFieldsMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; auto simpleMatcher = matcher.mutable_simple_atom_matcher(); @@ -597,7 +597,7 @@ TEST(AtomMatcherTest, TestMultiFieldsMatcher) { } TEST(AtomMatcherTest, TestIntComparisonMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; auto simpleMatcher = matcher.mutable_simple_atom_matcher(); @@ -654,7 +654,7 @@ TEST(AtomMatcherTest, TestIntComparisonMatcher) { } TEST(AtomMatcherTest, TestFloatComparisonMatcher) { - UidMap uidMap; + sp<UidMap> uidMap = new UidMap(); // Set up the matcher AtomMatcher matcher; auto simpleMatcher = matcher.mutable_simple_atom_matcher(); diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp index 6259757fe092..8dd608347064 100644 --- a/cmds/statsd/tests/MetricsManager_test.cpp +++ b/cmds/statsd/tests/MetricsManager_test.cpp @@ -28,7 +28,7 @@ #include "src/metrics/GaugeMetricProducer.h" #include "src/metrics/MetricProducer.h" #include "src/metrics/ValueMetricProducer.h" -#include "src/metrics/metrics_manager_util.h" +#include "src/metrics/parsing_utils/metrics_manager_util.h" #include "src/state/StateManager.h" #include "statsd_test_util.h" @@ -48,7 +48,6 @@ namespace statsd { namespace { const ConfigKey kConfigKey(0, 12345); -const long kAlertId = 3; const long timeBaseSec = 1000; @@ -90,287 +89,6 @@ StatsdConfig buildGoodConfig() { metric->set_bucket(ONE_MINUTE); metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/); metric->mutable_dimensions_in_what()->add_child()->set_field(1); - - config.add_no_report_metric(3); - - auto alert = config.add_alert(); - alert->set_id(kAlertId); - alert->set_metric_id(3); - alert->set_num_buckets(10); - alert->set_refractory_period_secs(100); - alert->set_trigger_if_sum_gt(100); - return config; -} - -StatsdConfig buildCircleMatchers() { - StatsdConfig config; - config.set_id(12345); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_IS_ON")); - - SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); - simpleAtomMatcher->add_field_value_matcher()->set_field( - 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); - simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( - 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); - - eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF")); - - AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); - combination->set_operation(LogicalOperation::OR); - combination->add_matcher(StringToId("SCREEN_IS_ON")); - // Circle dependency - combination->add_matcher(StringToId("SCREEN_ON_OR_OFF")); - - return config; -} - -StatsdConfig buildAlertWithUnknownMetric() { - StatsdConfig config; - config.set_id(12345); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_IS_ON")); - - CountMetric* metric = config.add_count_metric(); - metric->set_id(3); - metric->set_what(StringToId("SCREEN_IS_ON")); - metric->set_bucket(ONE_MINUTE); - metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/); - metric->mutable_dimensions_in_what()->add_child()->set_field(1); - - auto alert = config.add_alert(); - alert->set_id(3); - alert->set_metric_id(2); - alert->set_num_buckets(10); - alert->set_refractory_period_secs(100); - alert->set_trigger_if_sum_gt(100); - return config; -} - -StatsdConfig buildMissingMatchers() { - StatsdConfig config; - config.set_id(12345); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_IS_ON")); - - SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); - simpleAtomMatcher->add_field_value_matcher()->set_field( - 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); - simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( - 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); - - eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF")); - - AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); - combination->set_operation(LogicalOperation::OR); - combination->add_matcher(StringToId("SCREEN_IS_ON")); - // undefined matcher - combination->add_matcher(StringToId("ABC")); - - return config; -} - -StatsdConfig buildMissingPredicate() { - StatsdConfig config; - config.set_id(12345); - - CountMetric* metric = config.add_count_metric(); - metric->set_id(3); - metric->set_what(StringToId("SCREEN_EVENT")); - metric->set_bucket(ONE_MINUTE); - metric->set_condition(StringToId("SOME_CONDITION")); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_EVENT")); - - SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2); - - return config; -} - -StatsdConfig buildDimensionMetricsWithMultiTags() { - StatsdConfig config; - config.set_id(12345); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("BATTERY_VERY_LOW")); - SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2); - - eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("BATTERY_VERY_VERY_LOW")); - simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(3); - - eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("BATTERY_LOW")); - - AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); - combination->set_operation(LogicalOperation::OR); - combination->add_matcher(StringToId("BATTERY_VERY_LOW")); - combination->add_matcher(StringToId("BATTERY_VERY_VERY_LOW")); - - // Count process state changes, slice by uid, while SCREEN_IS_OFF - CountMetric* metric = config.add_count_metric(); - metric->set_id(3); - metric->set_what(StringToId("BATTERY_LOW")); - metric->set_bucket(ONE_MINUTE); - // This case is interesting. We want to dimension across two atoms. - metric->mutable_dimensions_in_what()->add_child()->set_field(1); - - auto alert = config.add_alert(); - alert->set_id(kAlertId); - alert->set_metric_id(3); - alert->set_num_buckets(10); - alert->set_refractory_period_secs(100); - alert->set_trigger_if_sum_gt(100); - return config; -} - -StatsdConfig buildCirclePredicates() { - StatsdConfig config; - config.set_id(12345); - - AtomMatcher* eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_IS_ON")); - - SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); - simpleAtomMatcher->add_field_value_matcher()->set_field( - 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); - simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( - 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); - - eventMatcher = config.add_atom_matcher(); - eventMatcher->set_id(StringToId("SCREEN_IS_OFF")); - - simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); - simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); - simpleAtomMatcher->add_field_value_matcher()->set_field( - 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); - simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( - 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/); - - auto condition = config.add_predicate(); - condition->set_id(StringToId("SCREEN_IS_ON")); - SimplePredicate* simplePredicate = condition->mutable_simple_predicate(); - simplePredicate->set_start(StringToId("SCREEN_IS_ON")); - simplePredicate->set_stop(StringToId("SCREEN_IS_OFF")); - - condition = config.add_predicate(); - condition->set_id(StringToId("SCREEN_IS_EITHER_ON_OFF")); - - Predicate_Combination* combination = condition->mutable_combination(); - combination->set_operation(LogicalOperation::OR); - combination->add_predicate(StringToId("SCREEN_IS_ON")); - combination->add_predicate(StringToId("SCREEN_IS_EITHER_ON_OFF")); - - return config; -} - -StatsdConfig buildConfigWithDifferentPredicates() { - StatsdConfig config; - config.set_id(12345); - - auto pulledAtomMatcher = - CreateSimpleAtomMatcher("SUBSYSTEM_SLEEP", util::SUBSYSTEM_SLEEP_STATE); - *config.add_atom_matcher() = pulledAtomMatcher; - auto screenOnAtomMatcher = CreateScreenTurnedOnAtomMatcher(); - *config.add_atom_matcher() = screenOnAtomMatcher; - auto screenOffAtomMatcher = CreateScreenTurnedOffAtomMatcher(); - *config.add_atom_matcher() = screenOffAtomMatcher; - auto batteryNoneAtomMatcher = CreateBatteryStateNoneMatcher(); - *config.add_atom_matcher() = batteryNoneAtomMatcher; - auto batteryUsbAtomMatcher = CreateBatteryStateUsbMatcher(); - *config.add_atom_matcher() = batteryUsbAtomMatcher; - - // Simple condition with InitialValue set to default (unknown). - auto screenOnUnknownPredicate = CreateScreenIsOnPredicate(); - *config.add_predicate() = screenOnUnknownPredicate; - - // Simple condition with InitialValue set to false. - auto screenOnFalsePredicate = config.add_predicate(); - screenOnFalsePredicate->set_id(StringToId("ScreenIsOnInitialFalse")); - SimplePredicate* simpleScreenOnFalsePredicate = - screenOnFalsePredicate->mutable_simple_predicate(); - simpleScreenOnFalsePredicate->set_start(screenOnAtomMatcher.id()); - simpleScreenOnFalsePredicate->set_stop(screenOffAtomMatcher.id()); - simpleScreenOnFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE); - - // Simple condition with InitialValue set to false. - auto onBatteryFalsePredicate = config.add_predicate(); - onBatteryFalsePredicate->set_id(StringToId("OnBatteryInitialFalse")); - SimplePredicate* simpleOnBatteryFalsePredicate = - onBatteryFalsePredicate->mutable_simple_predicate(); - simpleOnBatteryFalsePredicate->set_start(batteryNoneAtomMatcher.id()); - simpleOnBatteryFalsePredicate->set_stop(batteryUsbAtomMatcher.id()); - simpleOnBatteryFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE); - - // Combination condition with both simple condition InitialValues set to false. - auto screenOnFalseOnBatteryFalsePredicate = config.add_predicate(); - screenOnFalseOnBatteryFalsePredicate->set_id(StringToId("ScreenOnFalseOnBatteryFalse")); - screenOnFalseOnBatteryFalsePredicate->mutable_combination()->set_operation( - LogicalOperation::AND); - addPredicateToPredicateCombination(*screenOnFalsePredicate, - screenOnFalseOnBatteryFalsePredicate); - addPredicateToPredicateCombination(*onBatteryFalsePredicate, - screenOnFalseOnBatteryFalsePredicate); - - // Combination condition with one simple condition InitialValue set to unknown and one set to - // false. - auto screenOnUnknownOnBatteryFalsePredicate = config.add_predicate(); - screenOnUnknownOnBatteryFalsePredicate->set_id(StringToId("ScreenOnUnknowneOnBatteryFalse")); - screenOnUnknownOnBatteryFalsePredicate->mutable_combination()->set_operation( - LogicalOperation::AND); - addPredicateToPredicateCombination(screenOnUnknownPredicate, - screenOnUnknownOnBatteryFalsePredicate); - addPredicateToPredicateCombination(*onBatteryFalsePredicate, - screenOnUnknownOnBatteryFalsePredicate); - - // Simple condition metric with initial value false. - ValueMetric* metric1 = config.add_value_metric(); - metric1->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialFalse")); - metric1->set_what(pulledAtomMatcher.id()); - *metric1->mutable_value_field() = - CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); - metric1->set_bucket(FIVE_MINUTES); - metric1->set_condition(screenOnFalsePredicate->id()); - - // Simple condition metric with initial value unknown. - ValueMetric* metric2 = config.add_value_metric(); - metric2->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialUnknown")); - metric2->set_what(pulledAtomMatcher.id()); - *metric2->mutable_value_field() = - CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); - metric2->set_bucket(FIVE_MINUTES); - metric2->set_condition(screenOnUnknownPredicate.id()); - - // Combination condition metric with initial values false and false. - ValueMetric* metric3 = config.add_value_metric(); - metric3->set_id(StringToId("ValueSubsystemSleepWhileScreenOnFalseDeviceUnpluggedFalse")); - metric3->set_what(pulledAtomMatcher.id()); - *metric3->mutable_value_field() = - CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); - metric3->set_bucket(FIVE_MINUTES); - metric3->set_condition(screenOnFalseOnBatteryFalsePredicate->id()); - - // Combination condition metric with initial values unknown and false. - ValueMetric* metric4 = config.add_value_metric(); - metric4->set_id(StringToId("ValueSubsystemSleepWhileScreenOnUnknownDeviceUnpluggedFalse")); - metric4->set_what(pulledAtomMatcher.id()); - *metric4->mutable_value_field() = - CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); - metric4->set_bucket(FIVE_MINUTES); - metric4->set_condition(screenOnUnknownOnBatteryFalsePredicate->id()); - return config; } @@ -379,274 +97,6 @@ bool isSubset(const set<int32_t>& set1, const set<int32_t>& set2) { } } // anonymous namespace -TEST(MetricsManagerTest, TestInitialConditions) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildConfigWithDifferentPredicates(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_TRUE(initStatsdConfig( - kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, allConditionTrackers, - allMetricProducers, allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap, - deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, - noReportMetricIds)); - ASSERT_EQ(4u, allMetricProducers.size()); - ASSERT_EQ(5u, allConditionTrackers.size()); - - ConditionKey queryKey; - vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated); - - allConditionTrackers[3]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache); - allConditionTrackers[4]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache); - EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]); - EXPECT_EQ(ConditionState::kFalse, conditionCache[1]); - EXPECT_EQ(ConditionState::kFalse, conditionCache[2]); - EXPECT_EQ(ConditionState::kFalse, conditionCache[3]); - EXPECT_EQ(ConditionState::kUnknown, conditionCache[4]); - - EXPECT_EQ(ConditionState::kFalse, allMetricProducers[0]->mCondition); - EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[1]->mCondition); - EXPECT_EQ(ConditionState::kFalse, allMetricProducers[2]->mCondition); - EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[3]->mCondition); -} - -TEST(MetricsManagerTest, TestGoodConfig) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildGoodConfig(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); - ASSERT_EQ(1u, allMetricProducers.size()); - ASSERT_EQ(1u, allAnomalyTrackers.size()); - ASSERT_EQ(1u, noReportMetricIds.size()); - ASSERT_EQ(1u, alertTrackerMap.size()); - EXPECT_NE(alertTrackerMap.find(kAlertId), alertTrackerMap.end()); - EXPECT_EQ(alertTrackerMap.find(kAlertId)->second, 0); -} - -TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildDimensionMetricsWithMultiTags(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); -} - -TEST(MetricsManagerTest, TestCircleLogMatcherDependency) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildCircleMatchers(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); -} - -TEST(MetricsManagerTest, TestMissingMatchers) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildMissingMatchers(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); -} - -TEST(MetricsManagerTest, TestMissingPredicate) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildMissingPredicate(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, noReportMetricIds)); -} - -TEST(MetricsManagerTest, TestCirclePredicateDependency) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildCirclePredicates(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); -} - -TEST(MetricsManagerTest, testAlertWithUnknownMetric) { - UidMap uidMap; - sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - sp<AlarmMonitor> anomalyAlarmMonitor; - sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildAlertWithUnknownMetric(); - set<int> allTagIds; - vector<sp<LogMatchingTracker>> allAtomMatchers; - vector<sp<ConditionTracker>> allConditionTrackers; - vector<sp<MetricProducer>> allMetricProducers; - std::vector<sp<AnomalyTracker>> allAnomalyTrackers; - std::vector<sp<AlarmTracker>> allAlarmTrackers; - unordered_map<int, std::vector<int>> conditionToMetricMap; - unordered_map<int, std::vector<int>> trackerToMetricMap; - unordered_map<int, std::vector<int>> trackerToConditionMap; - unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; - unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; - unordered_map<int64_t, int> alertTrackerMap; - vector<int> metricsWithActivation; - std::set<int64_t> noReportMetricIds; - - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, - periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds, - allAtomMatchers, allConditionTrackers, allMetricProducers, - allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap, - activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, - alertTrackerMap, metricsWithActivation, - noReportMetricIds)); -} - TEST(MetricsManagerTest, TestLogSources) { string app1 = "app1"; set<int32_t> app1Uids = {1111, 11111}; @@ -680,7 +130,7 @@ TEST(MetricsManagerTest, TestLogSources) { sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildGoodConfig(); + StatsdConfig config; config.add_allowed_log_source("AID_SYSTEM"); config.add_allowed_log_source(app1); config.add_default_pull_packages("AID_SYSTEM"); @@ -744,7 +194,7 @@ TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom) { sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> periodicAlarmMonitor; - StatsdConfig config = buildGoodConfig(); + StatsdConfig config; config.add_whitelisted_atom_ids(3); config.add_whitelisted_atom_ids(4); diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp index caea42dfe032..d96ff8a1925b 100644 --- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp @@ -47,7 +47,6 @@ namespace { const ConfigKey kConfigKey(0, 12345); const int tagId = 1; const int64_t metricId = 123; -const int64_t atomMatcherId = 678; const int logEventMatcherIndex = 0; const int64_t bucketStartTimeNs = 10 * NS_PER_SEC; const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; @@ -94,11 +93,8 @@ TEST(GaugeMetricProducerTest, TestFirstBucket) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); - sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({ - new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + sp<EventMatcherWizard> eventMatcherWizard = + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -127,12 +123,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); @@ -217,12 +209,8 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPushedEvents) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, wizard, logEventMatcherIndex, eventMatcherWizard, @@ -301,12 +289,9 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPulled) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return()); @@ -378,12 +363,8 @@ TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); @@ -428,12 +409,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); int64_t conditionChangeNs = bucketStartTimeNs + 8; @@ -502,12 +479,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) { dim->set_field(tagId); dim->add_child()->set_field(1); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EXPECT_CALL(*wizard, query(_, _, _)) @@ -577,12 +550,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) { gaugeFieldMatcher->set_field(tagId); gaugeFieldMatcher->add_child()->set_field(2); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1, @@ -657,12 +626,8 @@ TEST(GaugeMetricProducerTest, TestPullOnTrigger) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) @@ -729,12 +694,8 @@ TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _)) @@ -807,12 +768,8 @@ TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 3, _)) diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index 98892507e78d..5524ebc86b36 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -46,7 +46,6 @@ namespace { const ConfigKey kConfigKey(0, 12345); const int tagId = 1; const int64_t metricId = 123; -const int64_t atomMatcherId = 678; const int logEventMatcherIndex = 0; const int64_t bucketStartTimeNs = 10000000000; const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; @@ -99,12 +98,8 @@ class ValueMetricProducerTestHelper { public: static sp<ValueMetricProducer> createValueProducerNoConditions( sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) { - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)) .WillOnce(Return()); @@ -122,12 +117,8 @@ public: static sp<ValueMetricProducer> createValueProducerWithCondition( sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric, ConditionState conditionAfterFirstBucketPrepared) { - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)) .WillOnce(Return()); @@ -147,12 +138,8 @@ public: sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric, vector<int32_t> slicedStateAtoms, unordered_map<int, unordered_map<int, int64_t>> stateGroupMap) { - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)) .WillOnce(Return()); @@ -172,12 +159,8 @@ public: vector<int32_t> slicedStateAtoms, unordered_map<int, unordered_map<int, int64_t>> stateGroupMap, ConditionState conditionAfterFirstBucketPrepared) { - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)) .WillOnce(Return()); @@ -237,12 +220,8 @@ TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); int64_t startTimeBase = 11; - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -267,12 +246,8 @@ TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) { TEST(ValueMetricProducerTest, TestFirstBucket) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -421,15 +396,11 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPartialBucketCreated) { TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); - auto keyValue = atomMatcher.add_field_value_matcher(); - keyValue->set_field(1); - keyValue->set_eq_int(3); + FieldValueMatcher fvm; + fvm.set_field(1); + fvm.set_eq_int(3); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex, {fvm}); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); @@ -698,12 +669,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { TEST_P(ValueMetricProducerTest_PartialBucket, TestPushedEvents) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -759,12 +726,8 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPushedEvents) { TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValue) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 150; @@ -820,12 +783,8 @@ TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); metric.set_split_bucket_for_app_upgrade(false); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); @@ -900,12 +859,8 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -944,12 +899,8 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -1015,12 +966,8 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -1360,12 +1307,8 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); metric.set_aggregation_type(ValueMetric::MIN); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -1404,12 +1347,8 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); metric.set_aggregation_type(ValueMetric::MAX); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -1447,12 +1386,8 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); metric.set_aggregation_type(ValueMetric::AVG); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -1495,12 +1430,8 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); metric.set_aggregation_type(ValueMetric::SUM); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -1539,12 +1470,8 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { metric.set_aggregation_type(ValueMetric::MIN); metric.set_use_diff(true); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -1611,12 +1538,8 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) { metric.set_aggregation_type(ValueMetric::MIN); metric.set_use_diff(true); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); @@ -2140,12 +2063,8 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) { TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) { ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); @@ -2963,12 +2882,8 @@ TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) { TEST(ValueMetricProducerTest, TestPullNeededFastDump) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); @@ -3001,12 +2916,8 @@ TEST(ValueMetricProducerTest, TestPullNeededFastDump) { TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); @@ -3045,12 +2956,8 @@ TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) { TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) { ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); - UidMap uidMap; - SimpleAtomMatcher atomMatcher; - atomMatcher.set_atom_id(tagId); sp<EventMatcherWizard> eventMatcherWizard = - new EventMatcherWizard({new SimpleLogMatchingTracker( - atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + createEventMatcherWizard(tagId, logEventMatcherIndex); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return()); diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp new file mode 100644 index 000000000000..6b50fe5387d7 --- /dev/null +++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp @@ -0,0 +1,382 @@ +// Copyright (C) 2020 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 "src/metrics/parsing_utils/config_update_utils.h" + +#include <gtest/gtest.h> +#include <private/android_filesystem_config.h> +#include <stdio.h> + +#include <set> +#include <unordered_map> +#include <vector> + +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" +#include "src/metrics/parsing_utils/metrics_manager_util.h" +#include "tests/statsd_test_util.h" + +using namespace testing; +using android::sp; +using android::os::statsd::Predicate; +using std::map; +using std::set; +using std::unordered_map; +using std::vector; + +#ifdef __ANDROID__ + +namespace android { +namespace os { +namespace statsd { + +namespace { + +ConfigKey key(123, 456); +const int64_t timeBaseNs = 1000; +sp<UidMap> uidMap = new UidMap(); +sp<StatsPullerManager> pullerManager = new StatsPullerManager(); +sp<AlarmMonitor> anomalyAlarmMonitor; +sp<AlarmMonitor> periodicAlarmMonitor; +set<int> allTagIds; +vector<sp<LogMatchingTracker>> oldAtomMatchers; +unordered_map<int64_t, int> oldLogTrackerMap; +vector<sp<ConditionTracker>> oldConditionTrackers; +vector<sp<MetricProducer>> oldMetricProducers; +std::vector<sp<AnomalyTracker>> oldAnomalyTrackers; +std::vector<sp<AlarmTracker>> oldAlarmTrackers; +unordered_map<int, std::vector<int>> conditionToMetricMap; +unordered_map<int, std::vector<int>> trackerToMetricMap; +unordered_map<int, std::vector<int>> trackerToConditionMap; +unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; +unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; +unordered_map<int64_t, int> alertTrackerMap; +vector<int> metricsWithActivation; +std::set<int64_t> noReportMetricIds; + +class ConfigUpdateTest : public ::testing::Test { +public: + ConfigUpdateTest() { + } + + void SetUp() override { + allTagIds.clear(); + oldAtomMatchers.clear(); + oldLogTrackerMap.clear(); + oldConditionTrackers.clear(); + oldMetricProducers.clear(); + oldAnomalyTrackers.clear(); + oldAlarmTrackers.clear(); + conditionToMetricMap.clear(); + trackerToMetricMap.clear(); + trackerToConditionMap.clear(); + activationAtomTrackerToMetricMap.clear(); + deactivationAtomTrackerToMetricMap.clear(); + alertTrackerMap.clear(); + metricsWithActivation.clear(); + noReportMetricIds.clear(); + } +}; + +bool initConfig(const StatsdConfig& config) { + return initStatsdConfig(key, config, uidMap, pullerManager, anomalyAlarmMonitor, + periodicAlarmMonitor, timeBaseNs, timeBaseNs, allTagIds, + oldAtomMatchers, oldLogTrackerMap, oldConditionTrackers, + oldMetricProducers, oldAnomalyTrackers, oldAlarmTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + alertTrackerMap, metricsWithActivation, noReportMetricIds); +} + +} // anonymous namespace + +TEST_F(ConfigUpdateTest, TestSimpleMatcherPreserve) { + StatsdConfig config; + AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10); + int64_t matcherId = matcher.id(); + *config.add_atom_matcher() = matcher; + + // Create an initial config. + EXPECT_TRUE(initConfig(config)); + + vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newLogTrackerMap; + newLogTrackerMap[matcherId] = 0; + EXPECT_TRUE(determineMatcherUpdateStatus(config, 0, oldLogTrackerMap, oldAtomMatchers, + newLogTrackerMap, matchersToUpdate, cycleTracker)); + EXPECT_EQ(matchersToUpdate[0], UPDATE_PRESERVE); +} + +TEST_F(ConfigUpdateTest, TestSimpleMatcherReplace) { + StatsdConfig config; + AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10); + *config.add_atom_matcher() = matcher; + + EXPECT_TRUE(initConfig(config)); + + StatsdConfig newConfig; + // Same id, different atom, so should be replaced. + AtomMatcher newMatcher = CreateSimpleAtomMatcher("TEST", /*atom=*/11); + int64_t matcherId = newMatcher.id(); + EXPECT_EQ(matcherId, matcher.id()); + *newConfig.add_atom_matcher() = newMatcher; + + vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN); + vector<bool> cycleTracker(1, false); + unordered_map<int64_t, int> newLogTrackerMap; + newLogTrackerMap[matcherId] = 0; + EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 0, oldLogTrackerMap, oldAtomMatchers, + newLogTrackerMap, matchersToUpdate, cycleTracker)); + EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestCombinationMatcherPreserve) { + StatsdConfig config; + AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10); + int64_t matcher1Id = matcher1.id(); + *config.add_atom_matcher() = matcher1; + + AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11); + *config.add_atom_matcher() = matcher2; + int64_t matcher2Id = matcher2.id(); + + AtomMatcher matcher3; + matcher3.set_id(StringToId("TEST3")); + AtomMatcher_Combination* combination = matcher3.mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(matcher1Id); + combination->add_matcher(matcher2Id); + int64_t matcher3Id = matcher3.id(); + *config.add_atom_matcher() = matcher3; + + EXPECT_TRUE(initConfig(config)); + + StatsdConfig newConfig; + unordered_map<int64_t, int> newLogTrackerMap; + // Same matchers, different order, all should be preserved. + *newConfig.add_atom_matcher() = matcher2; + newLogTrackerMap[matcher2Id] = 0; + *newConfig.add_atom_matcher() = matcher3; + newLogTrackerMap[matcher3Id] = 1; + *newConfig.add_atom_matcher() = matcher1; + newLogTrackerMap[matcher1Id] = 2; + + vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. It should recurse the two child matchers and preserve all 3. + EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldLogTrackerMap, oldAtomMatchers, + newLogTrackerMap, matchersToUpdate, cycleTracker)); + EXPECT_EQ(matchersToUpdate[0], UPDATE_PRESERVE); + EXPECT_EQ(matchersToUpdate[1], UPDATE_PRESERVE); + EXPECT_EQ(matchersToUpdate[2], UPDATE_PRESERVE); +} + +TEST_F(ConfigUpdateTest, TestCombinationMatcherReplace) { + StatsdConfig config; + AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10); + int64_t matcher1Id = matcher1.id(); + *config.add_atom_matcher() = matcher1; + + AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11); + *config.add_atom_matcher() = matcher2; + int64_t matcher2Id = matcher2.id(); + + AtomMatcher matcher3; + matcher3.set_id(StringToId("TEST3")); + AtomMatcher_Combination* combination = matcher3.mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(matcher1Id); + combination->add_matcher(matcher2Id); + int64_t matcher3Id = matcher3.id(); + *config.add_atom_matcher() = matcher3; + + EXPECT_TRUE(initConfig(config)); + + // Change the logical operation of the combination matcher, causing a replacement. + matcher3.mutable_combination()->set_operation(LogicalOperation::AND); + + StatsdConfig newConfig; + unordered_map<int64_t, int> newLogTrackerMap; + *newConfig.add_atom_matcher() = matcher2; + newLogTrackerMap[matcher2Id] = 0; + *newConfig.add_atom_matcher() = matcher3; + newLogTrackerMap[matcher3Id] = 1; + *newConfig.add_atom_matcher() = matcher1; + newLogTrackerMap[matcher1Id] = 2; + + vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. The simple matchers should not be evaluated. + EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldLogTrackerMap, oldAtomMatchers, + newLogTrackerMap, matchersToUpdate, cycleTracker)); + EXPECT_EQ(matchersToUpdate[0], UPDATE_UNKNOWN); + EXPECT_EQ(matchersToUpdate[1], UPDATE_REPLACE); + EXPECT_EQ(matchersToUpdate[2], UPDATE_UNKNOWN); +} + +TEST_F(ConfigUpdateTest, TestCombinationMatcherDepsChange) { + StatsdConfig config; + AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10); + int64_t matcher1Id = matcher1.id(); + *config.add_atom_matcher() = matcher1; + + AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11); + *config.add_atom_matcher() = matcher2; + int64_t matcher2Id = matcher2.id(); + + AtomMatcher matcher3; + matcher3.set_id(StringToId("TEST3")); + AtomMatcher_Combination* combination = matcher3.mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(matcher1Id); + combination->add_matcher(matcher2Id); + int64_t matcher3Id = matcher3.id(); + *config.add_atom_matcher() = matcher3; + + EXPECT_TRUE(initConfig(config)); + + // Change a dependency of matcher 3. + matcher2.mutable_simple_atom_matcher()->set_atom_id(12); + + StatsdConfig newConfig; + unordered_map<int64_t, int> newLogTrackerMap; + *newConfig.add_atom_matcher() = matcher2; + newLogTrackerMap[matcher2Id] = 0; + *newConfig.add_atom_matcher() = matcher3; + newLogTrackerMap[matcher3Id] = 1; + *newConfig.add_atom_matcher() = matcher1; + newLogTrackerMap[matcher1Id] = 2; + + vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN); + vector<bool> cycleTracker(3, false); + // Only update the combination. + EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldLogTrackerMap, oldAtomMatchers, + newLogTrackerMap, matchersToUpdate, cycleTracker)); + // Matcher 2 and matcher3 must be reevaluated. Matcher 1 might, but does not need to be. + EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE); + EXPECT_EQ(matchersToUpdate[1], UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestUpdateMatchers) { + StatsdConfig config; + // Will be preserved. + AtomMatcher simple1 = CreateSimpleAtomMatcher("SIMPLE1", /*atom=*/10); + int64_t simple1Id = simple1.id(); + *config.add_atom_matcher() = simple1; + + // Will be replaced. + AtomMatcher simple2 = CreateSimpleAtomMatcher("SIMPLE2", /*atom=*/11); + *config.add_atom_matcher() = simple2; + int64_t simple2Id = simple2.id(); + + // Will be removed. + AtomMatcher simple3 = CreateSimpleAtomMatcher("SIMPLE3", /*atom=*/12); + *config.add_atom_matcher() = simple3; + int64_t simple3Id = simple3.id(); + + // Will be preserved. + AtomMatcher combination1; + combination1.set_id(StringToId("combination1")); + AtomMatcher_Combination* combination = combination1.mutable_combination(); + combination->set_operation(LogicalOperation::NOT); + combination->add_matcher(simple1Id); + int64_t combination1Id = combination1.id(); + *config.add_atom_matcher() = combination1; + + // Will be replaced since it depends on simple2. + AtomMatcher combination2; + combination2.set_id(StringToId("combination2")); + combination = combination2.mutable_combination(); + combination->set_operation(LogicalOperation::AND); + combination->add_matcher(simple1Id); + combination->add_matcher(simple2Id); + int64_t combination2Id = combination2.id(); + *config.add_atom_matcher() = combination2; + + EXPECT_TRUE(initConfig(config)); + + // Change simple2, causing simple2 and combination2 to be replaced. + simple2.mutable_simple_atom_matcher()->set_atom_id(111); + + // 2 new matchers: simple4 and combination3: + AtomMatcher simple4 = CreateSimpleAtomMatcher("SIMPLE4", /*atom=*/13); + int64_t simple4Id = simple4.id(); + + AtomMatcher combination3; + combination3.set_id(StringToId("combination3")); + combination = combination3.mutable_combination(); + combination->set_operation(LogicalOperation::AND); + combination->add_matcher(simple4Id); + combination->add_matcher(simple2Id); + int64_t combination3Id = combination3.id(); + + StatsdConfig newConfig; + *newConfig.add_atom_matcher() = combination3; + *newConfig.add_atom_matcher() = simple2; + *newConfig.add_atom_matcher() = combination2; + *newConfig.add_atom_matcher() = simple1; + *newConfig.add_atom_matcher() = simple4; + *newConfig.add_atom_matcher() = combination1; + + set<int> newTagIds; + unordered_map<int64_t, int> newLogTrackerMap; + vector<sp<LogMatchingTracker>> newAtomMatchers; + EXPECT_TRUE(updateLogTrackers(newConfig, uidMap, oldLogTrackerMap, oldAtomMatchers, newTagIds, + newLogTrackerMap, newAtomMatchers)); + + ASSERT_EQ(newTagIds.size(), 3); + EXPECT_EQ(newTagIds.count(10), 1); + EXPECT_EQ(newTagIds.count(111), 1); + EXPECT_EQ(newTagIds.count(13), 1); + + ASSERT_EQ(newLogTrackerMap.size(), 6); + EXPECT_EQ(newLogTrackerMap.at(combination3Id), 0); + EXPECT_EQ(newLogTrackerMap.at(simple2Id), 1); + EXPECT_EQ(newLogTrackerMap.at(combination2Id), 2); + EXPECT_EQ(newLogTrackerMap.at(simple1Id), 3); + EXPECT_EQ(newLogTrackerMap.at(simple4Id), 4); + EXPECT_EQ(newLogTrackerMap.at(combination1Id), 5); + + ASSERT_EQ(newAtomMatchers.size(), 6); + // Make sure all atom matchers are initialized: + for (const sp<LogMatchingTracker>& tracker : newAtomMatchers) { + EXPECT_TRUE(tracker->mInitialized); + } + // Make sure preserved atom matchers are the same. + EXPECT_EQ(oldAtomMatchers[oldLogTrackerMap.at(simple1Id)], + newAtomMatchers[newLogTrackerMap.at(simple1Id)]); + EXPECT_EQ(oldAtomMatchers[oldLogTrackerMap.at(combination1Id)], + newAtomMatchers[newLogTrackerMap.at(combination1Id)]); + // Make sure replaced matchers are different. + EXPECT_NE(oldAtomMatchers[oldLogTrackerMap.at(simple2Id)], + newAtomMatchers[newLogTrackerMap.at(simple2Id)]); + EXPECT_NE(oldAtomMatchers[oldLogTrackerMap.at(combination2Id)], + newAtomMatchers[newLogTrackerMap.at(combination2Id)]); + + // Validation, make sure the matchers have the proper ids. Could do more checks here. + EXPECT_EQ(newAtomMatchers[0]->getId(), combination3Id); + EXPECT_EQ(newAtomMatchers[1]->getId(), simple2Id); + EXPECT_EQ(newAtomMatchers[2]->getId(), combination2Id); + EXPECT_EQ(newAtomMatchers[3]->getId(), simple1Id); + EXPECT_EQ(newAtomMatchers[4]->getId(), simple4Id); + EXPECT_EQ(newAtomMatchers[5]->getId(), combination1Id); +} + +} // namespace statsd +} // namespace os +} // namespace android + +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif diff --git a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp new file mode 100644 index 000000000000..4e97eaf6f149 --- /dev/null +++ b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp @@ -0,0 +1,708 @@ +// Copyright (C) 2020 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 "src/metrics/parsing_utils/metrics_manager_util.h" + +#include <gtest/gtest.h> +#include <private/android_filesystem_config.h> +#include <stdio.h> + +#include <set> +#include <unordered_map> +#include <vector> + +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" +#include "src/condition/ConditionTracker.h" +#include "src/matchers/LogMatchingTracker.h" +#include "src/metrics/CountMetricProducer.h" +#include "src/metrics/GaugeMetricProducer.h" +#include "src/metrics/MetricProducer.h" +#include "src/metrics/ValueMetricProducer.h" +#include "src/state/StateManager.h" +#include "tests/metrics/metrics_test_helper.h" +#include "tests/statsd_test_util.h" + +using namespace testing; +using android::sp; +using android::os::statsd::Predicate; +using std::map; +using std::set; +using std::unordered_map; +using std::vector; + +#ifdef __ANDROID__ + +namespace android { +namespace os { +namespace statsd { + +namespace { +const ConfigKey kConfigKey(0, 12345); +const long kAlertId = 3; + +const long timeBaseSec = 1000; + +StatsdConfig buildGoodConfig() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_ON")); + + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_OFF")); + + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF")); + + AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(StringToId("SCREEN_IS_ON")); + combination->add_matcher(StringToId("SCREEN_IS_OFF")); + + CountMetric* metric = config.add_count_metric(); + metric->set_id(3); + metric->set_what(StringToId("SCREEN_IS_ON")); + metric->set_bucket(ONE_MINUTE); + metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/); + metric->mutable_dimensions_in_what()->add_child()->set_field(1); + + config.add_no_report_metric(3); + + auto alert = config.add_alert(); + alert->set_id(kAlertId); + alert->set_metric_id(3); + alert->set_num_buckets(10); + alert->set_refractory_period_secs(100); + alert->set_trigger_if_sum_gt(100); + return config; +} + +StatsdConfig buildCircleMatchers() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_ON")); + + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF")); + + AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(StringToId("SCREEN_IS_ON")); + // Circle dependency + combination->add_matcher(StringToId("SCREEN_ON_OR_OFF")); + + return config; +} + +StatsdConfig buildAlertWithUnknownMetric() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_ON")); + + CountMetric* metric = config.add_count_metric(); + metric->set_id(3); + metric->set_what(StringToId("SCREEN_IS_ON")); + metric->set_bucket(ONE_MINUTE); + metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/); + metric->mutable_dimensions_in_what()->add_child()->set_field(1); + + auto alert = config.add_alert(); + alert->set_id(3); + alert->set_metric_id(2); + alert->set_num_buckets(10); + alert->set_refractory_period_secs(100); + alert->set_trigger_if_sum_gt(100); + return config; +} + +StatsdConfig buildMissingMatchers() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_ON")); + + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF")); + + AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(StringToId("SCREEN_IS_ON")); + // undefined matcher + combination->add_matcher(StringToId("ABC")); + + return config; +} + +StatsdConfig buildMissingPredicate() { + StatsdConfig config; + config.set_id(12345); + + CountMetric* metric = config.add_count_metric(); + metric->set_id(3); + metric->set_what(StringToId("SCREEN_EVENT")); + metric->set_bucket(ONE_MINUTE); + metric->set_condition(StringToId("SOME_CONDITION")); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_EVENT")); + + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2); + + return config; +} + +StatsdConfig buildDimensionMetricsWithMultiTags() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("BATTERY_VERY_LOW")); + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("BATTERY_VERY_VERY_LOW")); + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(3); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("BATTERY_LOW")); + + AtomMatcher_Combination* combination = eventMatcher->mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(StringToId("BATTERY_VERY_LOW")); + combination->add_matcher(StringToId("BATTERY_VERY_VERY_LOW")); + + // Count process state changes, slice by uid, while SCREEN_IS_OFF + CountMetric* metric = config.add_count_metric(); + metric->set_id(3); + metric->set_what(StringToId("BATTERY_LOW")); + metric->set_bucket(ONE_MINUTE); + // This case is interesting. We want to dimension across two atoms. + metric->mutable_dimensions_in_what()->add_child()->set_field(1); + + auto alert = config.add_alert(); + alert->set_id(kAlertId); + alert->set_metric_id(3); + alert->set_num_buckets(10); + alert->set_refractory_period_secs(100); + alert->set_trigger_if_sum_gt(100); + return config; +} + +StatsdConfig buildCirclePredicates() { + StatsdConfig config; + config.set_id(12345); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_ON")); + + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(StringToId("SCREEN_IS_OFF")); + + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/); + + auto condition = config.add_predicate(); + condition->set_id(StringToId("SCREEN_IS_ON")); + SimplePredicate* simplePredicate = condition->mutable_simple_predicate(); + simplePredicate->set_start(StringToId("SCREEN_IS_ON")); + simplePredicate->set_stop(StringToId("SCREEN_IS_OFF")); + + condition = config.add_predicate(); + condition->set_id(StringToId("SCREEN_IS_EITHER_ON_OFF")); + + Predicate_Combination* combination = condition->mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_predicate(StringToId("SCREEN_IS_ON")); + combination->add_predicate(StringToId("SCREEN_IS_EITHER_ON_OFF")); + + return config; +} + +StatsdConfig buildConfigWithDifferentPredicates() { + StatsdConfig config; + config.set_id(12345); + + auto pulledAtomMatcher = + CreateSimpleAtomMatcher("SUBSYSTEM_SLEEP", util::SUBSYSTEM_SLEEP_STATE); + *config.add_atom_matcher() = pulledAtomMatcher; + auto screenOnAtomMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = screenOnAtomMatcher; + auto screenOffAtomMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = screenOffAtomMatcher; + auto batteryNoneAtomMatcher = CreateBatteryStateNoneMatcher(); + *config.add_atom_matcher() = batteryNoneAtomMatcher; + auto batteryUsbAtomMatcher = CreateBatteryStateUsbMatcher(); + *config.add_atom_matcher() = batteryUsbAtomMatcher; + + // Simple condition with InitialValue set to default (unknown). + auto screenOnUnknownPredicate = CreateScreenIsOnPredicate(); + *config.add_predicate() = screenOnUnknownPredicate; + + // Simple condition with InitialValue set to false. + auto screenOnFalsePredicate = config.add_predicate(); + screenOnFalsePredicate->set_id(StringToId("ScreenIsOnInitialFalse")); + SimplePredicate* simpleScreenOnFalsePredicate = + screenOnFalsePredicate->mutable_simple_predicate(); + simpleScreenOnFalsePredicate->set_start(screenOnAtomMatcher.id()); + simpleScreenOnFalsePredicate->set_stop(screenOffAtomMatcher.id()); + simpleScreenOnFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE); + + // Simple condition with InitialValue set to false. + auto onBatteryFalsePredicate = config.add_predicate(); + onBatteryFalsePredicate->set_id(StringToId("OnBatteryInitialFalse")); + SimplePredicate* simpleOnBatteryFalsePredicate = + onBatteryFalsePredicate->mutable_simple_predicate(); + simpleOnBatteryFalsePredicate->set_start(batteryNoneAtomMatcher.id()); + simpleOnBatteryFalsePredicate->set_stop(batteryUsbAtomMatcher.id()); + simpleOnBatteryFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE); + + // Combination condition with both simple condition InitialValues set to false. + auto screenOnFalseOnBatteryFalsePredicate = config.add_predicate(); + screenOnFalseOnBatteryFalsePredicate->set_id(StringToId("ScreenOnFalseOnBatteryFalse")); + screenOnFalseOnBatteryFalsePredicate->mutable_combination()->set_operation( + LogicalOperation::AND); + addPredicateToPredicateCombination(*screenOnFalsePredicate, + screenOnFalseOnBatteryFalsePredicate); + addPredicateToPredicateCombination(*onBatteryFalsePredicate, + screenOnFalseOnBatteryFalsePredicate); + + // Combination condition with one simple condition InitialValue set to unknown and one set to + // false. + auto screenOnUnknownOnBatteryFalsePredicate = config.add_predicate(); + screenOnUnknownOnBatteryFalsePredicate->set_id(StringToId("ScreenOnUnknowneOnBatteryFalse")); + screenOnUnknownOnBatteryFalsePredicate->mutable_combination()->set_operation( + LogicalOperation::AND); + addPredicateToPredicateCombination(screenOnUnknownPredicate, + screenOnUnknownOnBatteryFalsePredicate); + addPredicateToPredicateCombination(*onBatteryFalsePredicate, + screenOnUnknownOnBatteryFalsePredicate); + + // Simple condition metric with initial value false. + ValueMetric* metric1 = config.add_value_metric(); + metric1->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialFalse")); + metric1->set_what(pulledAtomMatcher.id()); + *metric1->mutable_value_field() = + CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); + metric1->set_bucket(FIVE_MINUTES); + metric1->set_condition(screenOnFalsePredicate->id()); + + // Simple condition metric with initial value unknown. + ValueMetric* metric2 = config.add_value_metric(); + metric2->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialUnknown")); + metric2->set_what(pulledAtomMatcher.id()); + *metric2->mutable_value_field() = + CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); + metric2->set_bucket(FIVE_MINUTES); + metric2->set_condition(screenOnUnknownPredicate.id()); + + // Combination condition metric with initial values false and false. + ValueMetric* metric3 = config.add_value_metric(); + metric3->set_id(StringToId("ValueSubsystemSleepWhileScreenOnFalseDeviceUnpluggedFalse")); + metric3->set_what(pulledAtomMatcher.id()); + *metric3->mutable_value_field() = + CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); + metric3->set_bucket(FIVE_MINUTES); + metric3->set_condition(screenOnFalseOnBatteryFalsePredicate->id()); + + // Combination condition metric with initial values unknown and false. + ValueMetric* metric4 = config.add_value_metric(); + metric4->set_id(StringToId("ValueSubsystemSleepWhileScreenOnUnknownDeviceUnpluggedFalse")); + metric4->set_what(pulledAtomMatcher.id()); + *metric4->mutable_value_field() = + CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */}); + metric4->set_bucket(FIVE_MINUTES); + metric4->set_condition(screenOnUnknownOnBatteryFalsePredicate->id()); + + return config; +} +} // anonymous namespace + +TEST(MetricsManagerTest, TestInitialConditions) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildConfigWithDifferentPredicates(); + set<int> allTagIds; + vector<sp<LogMatchingTracker>> allAtomMatchers; + unordered_map<int64_t, int> logTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + vector<sp<MetricProducer>> allMetricProducers; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + std::set<int64_t> noReportMetricIds; + + EXPECT_TRUE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, + metricsWithActivation, noReportMetricIds)); + ASSERT_EQ(4u, allMetricProducers.size()); + ASSERT_EQ(5u, allConditionTrackers.size()); + + ConditionKey queryKey; + vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated); + + allConditionTrackers[3]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache); + allConditionTrackers[4]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache); + EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]); + EXPECT_EQ(ConditionState::kFalse, conditionCache[1]); + EXPECT_EQ(ConditionState::kFalse, conditionCache[2]); + EXPECT_EQ(ConditionState::kFalse, conditionCache[3]); + EXPECT_EQ(ConditionState::kUnknown, conditionCache[4]); + + EXPECT_EQ(ConditionState::kFalse, allMetricProducers[0]->mCondition); + EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[1]->mCondition); + EXPECT_EQ(ConditionState::kFalse, allMetricProducers[2]->mCondition); + EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[3]->mCondition); +} + +TEST(MetricsManagerTest, TestGoodConfig) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildGoodConfig(); + set<int> allTagIds; + vector<sp<LogMatchingTracker>> allAtomMatchers; + unordered_map<int64_t, int> logTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + vector<sp<MetricProducer>> allMetricProducers; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + std::set<int64_t> noReportMetricIds; + + EXPECT_TRUE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, + metricsWithActivation, noReportMetricIds)); + ASSERT_EQ(1u, allMetricProducers.size()); + ASSERT_EQ(1u, allAnomalyTrackers.size()); + ASSERT_EQ(1u, noReportMetricIds.size()); + ASSERT_EQ(1u, alertTrackerMap.size()); + EXPECT_NE(alertTrackerMap.find(kAlertId), alertTrackerMap.end()); + EXPECT_EQ(alertTrackerMap.find(kAlertId)->second, 0); +} + +TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildDimensionMetricsWithMultiTags(); + set<int> allTagIds; + vector<sp<LogMatchingTracker>> allAtomMatchers; + unordered_map<int64_t, int> logTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + vector<sp<MetricProducer>> allMetricProducers; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + std::set<int64_t> noReportMetricIds; + + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, + metricsWithActivation, noReportMetricIds)); +} + +TEST(MetricsManagerTest, TestCircleLogMatcherDependency) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildCircleMatchers(); + set<int> allTagIds; + vector<sp<LogMatchingTracker>> allAtomMatchers; + unordered_map<int64_t, int> logTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + vector<sp<MetricProducer>> allMetricProducers; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + std::set<int64_t> noReportMetricIds; + + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, + metricsWithActivation, noReportMetricIds)); +} + +TEST(MetricsManagerTest, TestMissingMatchers) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildMissingMatchers(); + set<int> allTagIds; + vector<sp<LogMatchingTracker>> allAtomMatchers; + unordered_map<int64_t, int> logTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + vector<sp<MetricProducer>> allMetricProducers; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + std::set<int64_t> noReportMetricIds; + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, + metricsWithActivation, noReportMetricIds)); +} + +TEST(MetricsManagerTest, TestMissingPredicate) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildMissingPredicate(); + set<int> allTagIds; + vector<sp<LogMatchingTracker>> allAtomMatchers; + unordered_map<int64_t, int> logTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + vector<sp<MetricProducer>> allMetricProducers; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + std::set<int64_t> noReportMetricIds; + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, + metricsWithActivation, noReportMetricIds)); +} + +TEST(MetricsManagerTest, TestCirclePredicateDependency) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildCirclePredicates(); + set<int> allTagIds; + vector<sp<LogMatchingTracker>> allAtomMatchers; + unordered_map<int64_t, int> logTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + vector<sp<MetricProducer>> allMetricProducers; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + std::set<int64_t> noReportMetricIds; + + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, + metricsWithActivation, noReportMetricIds)); +} + +TEST(MetricsManagerTest, testAlertWithUnknownMetric) { + sp<UidMap> uidMap = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> periodicAlarmMonitor; + StatsdConfig config = buildAlertWithUnknownMetric(); + set<int> allTagIds; + vector<sp<LogMatchingTracker>> allAtomMatchers; + unordered_map<int64_t, int> logTrackerMap; + vector<sp<ConditionTracker>> allConditionTrackers; + vector<sp<MetricProducer>> allMetricProducers; + std::vector<sp<AnomalyTracker>> allAnomalyTrackers; + std::vector<sp<AlarmTracker>> allAlarmTrackers; + unordered_map<int, std::vector<int>> conditionToMetricMap; + unordered_map<int, std::vector<int>> trackerToMetricMap; + unordered_map<int, std::vector<int>> trackerToConditionMap; + unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap; + unordered_map<int64_t, int> alertTrackerMap; + vector<int> metricsWithActivation; + std::set<int64_t> noReportMetricIds; + + EXPECT_FALSE(initStatsdConfig( + kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap, + metricsWithActivation, noReportMetricIds)); +} + +TEST(MetricsManagerTest, TestCreateLogTrackerInvalidMatcher) { + sp<UidMap> uidMap = new UidMap(); + AtomMatcher matcher; + matcher.set_id(21); + EXPECT_EQ(createLogTracker(matcher, 0, uidMap), nullptr); +} + +TEST(MetricsManagerTest, TestCreateLogTrackerSimple) { + int index = 1; + int64_t id = 123; + sp<UidMap> uidMap = new UidMap(); + AtomMatcher matcher; + matcher.set_id(id); + SimpleAtomMatcher* simpleAtomMatcher = matcher.mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(util::SCREEN_STATE_CHANGED); + simpleAtomMatcher->add_field_value_matcher()->set_field( + 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/); + simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int( + android::view::DisplayStateEnum::DISPLAY_STATE_ON); + + sp<LogMatchingTracker> tracker = createLogTracker(matcher, index, uidMap); + EXPECT_NE(tracker, nullptr); + + EXPECT_TRUE(tracker->mInitialized); + EXPECT_EQ(tracker->getId(), id); + EXPECT_EQ(tracker->mIndex, index); + const set<int>& atomIds = tracker->getAtomIds(); + ASSERT_EQ(atomIds.size(), 1); + EXPECT_EQ(atomIds.count(util::SCREEN_STATE_CHANGED), 1); +} + +TEST(MetricsManagerTest, TestCreateLogTrackerCombination) { + int index = 1; + int64_t id = 123; + sp<UidMap> uidMap = new UidMap(); + AtomMatcher matcher; + matcher.set_id(id); + AtomMatcher_Combination* combination = matcher.mutable_combination(); + combination->set_operation(LogicalOperation::OR); + combination->add_matcher(123); + combination->add_matcher(223); + + sp<LogMatchingTracker> tracker = createLogTracker(matcher, index, uidMap); + EXPECT_NE(tracker, nullptr); + + // Combination matchers need to be initialized first. + EXPECT_FALSE(tracker->mInitialized); + EXPECT_EQ(tracker->getId(), id); + EXPECT_EQ(tracker->mIndex, index); + const set<int>& atomIds = tracker->getAtomIds(); + ASSERT_EQ(atomIds.size(), 0); +} + +} // namespace statsd +} // namespace os +} // namespace android + +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index cee83725d075..0be983f2a9b0 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -15,6 +15,8 @@ #include "statsd_test_util.h" #include <aidl/android/util/StatsEventParcel.h> + +#include "matchers/SimpleLogMatchingTracker.h" #include "stats_event.h" using aidl::android::util::StatsEventParcel; @@ -996,6 +998,20 @@ int64_t StringToId(const string& str) { return static_cast<int64_t>(std::hash<std::string>()(str)); } +sp<EventMatcherWizard> createEventMatcherWizard( + int tagId, int matcherIndex, const vector<FieldValueMatcher>& fieldValueMatchers) { + sp<UidMap> uidMap = new UidMap(); + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + for (const FieldValueMatcher& fvm : fieldValueMatchers) { + *atomMatcher.add_field_value_matcher() = fvm; + } + uint64_t matcherHash = 0x12345678; + int64_t matcherId = 678; + return new EventMatcherWizard({new SimpleLogMatchingTracker(matcherId, matcherIndex, + matcherHash, atomMatcher, uidMap)}); +} + void ValidateWakelockAttributionUidAndTagDimension(const DimensionsValue& value, const int atomId, const int uid, const string& tag) { EXPECT_EQ(value.field(), atomId); diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h index 3dcf4ecce054..1220019e2353 100644 --- a/cmds/statsd/tests/statsd_test_util.h +++ b/cmds/statsd/tests/statsd_test_util.h @@ -25,6 +25,7 @@ #include "src/StatsLogProcessor.h" #include "src/hash.h" #include "src/logd/LogEvent.h" +#include "src/matchers/EventMatcherWizard.h" #include "src/packages/UidMap.h" #include "src/stats_log_util.h" #include "stats_event.h" @@ -335,6 +336,9 @@ void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events); int64_t StringToId(const string& str); +sp<EventMatcherWizard> createEventMatcherWizard( + int tagId, int matcherIndex, const std::vector<FieldValueMatcher>& fieldValueMatchers = {}); + void ValidateWakelockAttributionUidAndTagDimension(const DimensionsValue& value, const int atomId, const int uid, const string& tag); void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid); diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt index ab2f42b97e3b..f43bd2bd61b9 100644 --- a/config/boot-image-profile.txt +++ b/config/boot-image-profile.txt @@ -33629,6 +33629,35 @@ HSPLjava/math/BigInteger;-><init>([B)V HSPLjava/math/BigInteger;->abs()Ljava/math/BigInteger; HSPLjava/math/BigInteger;->add(Ljava/math/BigInteger;)Ljava/math/BigInteger; HSPLjava/math/BigInteger;->bitLength()I +#Temporary manual additions to avoid slowing tests down too much +#Carefully positioned for clean merge +HSPLjava/math/BigInteger;->add([IJ)[I +HSPLjava/math/BigInteger;->add([I[I)[I +HSPLjava/math/BigInteger;->subtract([IJ)[I +HSPLjava/math/BigInteger;->subtract([I[I)[I +HSPLjava/math/BigInteger;->jacobiSymbol(ILjava/math/BigInteger;)I +HSPLjava/math/BigInteger;->lucasLehmerSequence(ILjava/math/BigInteger;Ljava/math/BigInteger;)Ljava/math/BigInteger; +HSPLjava/math/BigInteger;->multiplyToLen([II[II[I)[I +HSPLjava/math/MutableBigInteger;->add(Ljava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->addShifted(Ljava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->subtract(Ljava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->difference(Ljava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->divideKnuth(Ljava/math/MutableBigInteger;Ljava/math/MutableBigInteger;Z)Ljava/math/MutableBigInteger; +HSPLjava/math/MutableBigInteger;->divideMagnitude(Ljava/math/MutableBigInteger;Ljava/math/MutableBigInteger;Z)Ljava/math/MutableBigInteger; +HSPLjava/math/MutableBigInteger;->divideLongMagnitude(JLjava/math/MutableBigInteger;)Ljava/math/MutableBigInteger; +HSPLjava/math/MutableBigInteger;->divideOneWord(ILjava/math/MutableBigInteger;)I +HSPLjava/math/MutableBigInteger;->divadd([I[II)I +HSPLjava/math/MutableBigInteger;->mulsub([I[IIII)I +HSPLjava/math/MutableBigInteger;->mulsubBorrow([I[IIII)I +HSPLjava/math/MutableBigInteger;->copyAndShift([III[III)V +HSPLjava/math/MutableBigInteger;->multiply(Ljava/math/MutableBigInteger;Ljava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->mul(ILjava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->multiply(ILjava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->primitiveRightShift(I)I +HSPLjava/math/MutableBigInteger;->primitiveLeftShift(I)I +HSPLjava/math/MutableBigInteger;->binaryGCD(Ljava/math/MutableBigInteger;)Ljava/math/MutableBigInteger; +HSPLjava/math/MutableBigInteger;->binaryGCD(II)I +#End of maual additions HSPLjava/math/BigInteger;->compareTo(Ljava/math/BigInteger;)I HSPLjava/math/BigInteger;->divide(Ljava/math/BigInteger;)Ljava/math/BigInteger; HSPLjava/math/BigInteger;->divideAndRemainder(Ljava/math/BigInteger;)[Ljava/math/BigInteger; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 522b8cc5a46f..5c4951e23ea2 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -3827,6 +3827,12 @@ public class Activity extends ContextThemeWrapper } catch (RemoteException e) { finishAfterTransition(); } + + // Activity was launched when user tapped a link in the Autofill Save UI - Save UI must + // be restored now. + if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) { + restoreAutofillSaveUi(); + } } /** diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 7cec717f96e0..d67b98620f37 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -424,9 +424,14 @@ public final class ActivityThread extends ClientTransactionHandler { final String authority; final int userId; + @GuardedBy("mLock") + ContentProviderHolder mHolder; // Temp holder to be used between notifier and waiter + Object mLock; // The lock to be used to get notified when the provider is ready + public ProviderKey(String authority, int userId) { this.authority = authority; this.userId = userId; + this.mLock = new Object(); } @Override @@ -440,7 +445,11 @@ public final class ActivityThread extends ClientTransactionHandler { @Override public int hashCode() { - return ((authority != null) ? authority.hashCode() : 0) ^ userId; + return hashCode(authority, userId); + } + + public static int hashCode(final String auth, final int userIdent) { + return ((auth != null) ? auth.hashCode() : 0) ^ userIdent; } } @@ -461,9 +470,8 @@ public final class ActivityThread extends ClientTransactionHandler { // Mitigation for b/74523247: Used to serialize calls to AM.getContentProvider(). // Note we never removes items from this map but that's okay because there are only so many // users and so many authorities. - // TODO Remove it once we move CPR.wait() from AMS to the client side. - @GuardedBy("mGetProviderLocks") - final ArrayMap<ProviderKey, Object> mGetProviderLocks = new ArrayMap<>(); + @GuardedBy("mGetProviderKeys") + final SparseArray<ProviderKey> mGetProviderKeys = new SparseArray<>(); final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>(); @@ -1756,6 +1764,16 @@ public final class ActivityThread extends ClientTransactionHandler { ActivityThread.this, activityToken, actionId, arguments, cancellationSignal, resultCallback)); } + + @Override + public void notifyContentProviderPublishStatus(@NonNull ContentProviderHolder holder, + @NonNull String auth, int userId, boolean published) { + final ProviderKey key = getGetProviderKey(auth, userId); + synchronized (key.mLock) { + key.mHolder = holder; + key.mLock.notifyAll(); + } + } } private @NonNull SafeCancellationTransport createSafeCancellationTransport( @@ -6807,13 +6825,33 @@ public final class ActivityThread extends ClientTransactionHandler { // provider since it might take a long time to run and it could also potentially // be re-entrant in the case where the provider is in the same process. ContentProviderHolder holder = null; + final ProviderKey key = getGetProviderKey(auth, userId); try { - synchronized (getGetProviderLock(auth, userId)) { + synchronized (key) { holder = ActivityManager.getService().getContentProvider( getApplicationThread(), c.getOpPackageName(), auth, userId, stable); + // If the returned holder is non-null but its provider is null and it's not + // local, we'll need to wait for the publishing of the provider. + if (holder != null && holder.provider == null && !holder.mLocal) { + synchronized (key.mLock) { + key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS); + holder = key.mHolder; + } + if (holder != null && holder.provider == null) { + // probably timed out + holder = null; + } + } } } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); + } catch (InterruptedException e) { + holder = null; + } finally { + // Clear the holder from the key since the key itself is never cleared. + synchronized (key.mLock) { + key.mHolder = null; + } } if (holder == null) { if (UserManager.get(c).isUserUnlocked(userId)) { @@ -6831,13 +6869,13 @@ public final class ActivityThread extends ClientTransactionHandler { return holder.provider; } - private Object getGetProviderLock(String auth, int userId) { - final ProviderKey key = new ProviderKey(auth, userId); - synchronized (mGetProviderLocks) { - Object lock = mGetProviderLocks.get(key); + private ProviderKey getGetProviderKey(String auth, int userId) { + final int key = ProviderKey.hashCode(auth, userId); + synchronized (mGetProviderKeys) { + ProviderKey lock = mGetProviderKeys.get(key); if (lock == null) { - lock = key; - mGetProviderLocks.put(key, lock); + lock = new ProviderKey(auth, userId); + mGetProviderKeys.put(key, lock); } return lock; } diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index dedd8705ef55..676c6c01d349 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -684,8 +684,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public int checkPermission(String permName, String pkgName) { - return PermissionManager - .checkPackageNamePermission(permName, pkgName, getUserId()); + return PermissionManager.checkPackageNamePermission(permName, pkgName, getUserId()); } @Override diff --git a/core/java/android/app/ContentProviderHolder.java b/core/java/android/app/ContentProviderHolder.java index 3d745831ce1c..e330a30de7b0 100644 --- a/core/java/android/app/ContentProviderHolder.java +++ b/core/java/android/app/ContentProviderHolder.java @@ -39,6 +39,11 @@ public class ContentProviderHolder implements Parcelable { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean noReleaseNeeded; + /** + * Whether the provider here is a local provider or not. + */ + public boolean mLocal; + @UnsupportedAppUsage public ContentProviderHolder(ProviderInfo _info) { info = _info; @@ -59,6 +64,7 @@ public class ContentProviderHolder implements Parcelable { } dest.writeStrongBinder(connection); dest.writeInt(noReleaseNeeded ? 1 : 0); + dest.writeInt(mLocal ? 1 : 0); } public static final @android.annotation.NonNull Parcelable.Creator<ContentProviderHolder> CREATOR @@ -81,5 +87,6 @@ public class ContentProviderHolder implements Parcelable { source.readStrongBinder()); connection = source.readStrongBinder(); noReleaseNeeded = source.readInt() != 0; + mLocal = source.readInt() != 0; } -}
\ No newline at end of file +} diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 93dfc79109a6..f37ca61ba69f 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -461,7 +461,7 @@ interface IActivityManager { @UnsupportedAppUsage Rect getTaskBounds(int taskId); @UnsupportedAppUsage - boolean setProcessMemoryTrimLevel(in String process, int uid, int level); + boolean setProcessMemoryTrimLevel(in String process, int userId, int level); // Start of L transactions diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 24da50481df3..dc9918ade9c2 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -16,6 +16,7 @@ package android.app; +import android.app.ContentProviderHolder; import android.app.IInstrumentationWatcher; import android.app.IUiAutomationConnection; import android.app.ProfilerInfo; @@ -147,4 +148,6 @@ oneway interface IApplicationThread { void performDirectAction(IBinder activityToken, String actionId, in Bundle arguments, in RemoteCallback cancellationCallback, in RemoteCallback resultCallback); + void notifyContentProviderPublishStatus(in ContentProviderHolder holder, String auth, + int userId, boolean published); } diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl index 8c3180b400ef..4c9e400681ee 100644 --- a/core/java/android/app/IUiAutomationConnection.aidl +++ b/core/java/android/app/IUiAutomationConnection.aidl @@ -39,7 +39,7 @@ interface IUiAutomationConnection { boolean injectInputEvent(in InputEvent event, boolean sync); void syncInputTransactions(); boolean setRotation(int rotation); - Bitmap takeScreenshot(in Rect crop, int rotation); + Bitmap takeScreenshot(in Rect crop); boolean clearWindowContentFrameStats(int windowId); WindowContentFrameStats getWindowContentFrameStats(int windowId); void clearWindowAnimationFrameStats(); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 68e65612971c..6f3e89229e4c 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1492,6 +1492,7 @@ public class Notification implements Parcelable private boolean mAllowGeneratedReplies = true; private final @SemanticAction int mSemanticAction; private final boolean mIsContextual; + private boolean mAuthenticationRequired; /** * Small icon representing the action. @@ -1528,6 +1529,7 @@ public class Notification implements Parcelable mAllowGeneratedReplies = in.readInt() == 1; mSemanticAction = in.readInt(); mIsContextual = in.readInt() == 1; + mAuthenticationRequired = in.readInt() == 1; } /** @@ -1536,13 +1538,14 @@ public class Notification implements Parcelable @Deprecated public Action(int icon, CharSequence title, PendingIntent intent) { this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true, - SEMANTIC_ACTION_NONE, false /* isContextual */); + SEMANTIC_ACTION_NONE, false /* isContextual */, false /* requireAuth */); } /** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */ private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras, RemoteInput[] remoteInputs, boolean allowGeneratedReplies, - @SemanticAction int semanticAction, boolean isContextual) { + @SemanticAction int semanticAction, boolean isContextual, + boolean requireAuth) { this.mIcon = icon; if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) { this.icon = icon.getResId(); @@ -1554,6 +1557,7 @@ public class Notification implements Parcelable this.mAllowGeneratedReplies = allowGeneratedReplies; this.mSemanticAction = semanticAction; this.mIsContextual = isContextual; + this.mAuthenticationRequired = requireAuth; } /** @@ -1624,6 +1628,17 @@ public class Notification implements Parcelable } /** + * Returns whether the OS should only send this action's {@link PendingIntent} on an + * unlocked device. + * + * If the device is locked when the action is invoked, the OS should show the keyguard and + * require successful authentication before invoking the intent. + */ + public boolean isAuthenticationRequired() { + return mAuthenticationRequired; + } + + /** * Builder class for {@link Action} objects. */ public static final class Builder { @@ -1635,6 +1650,7 @@ public class Notification implements Parcelable @Nullable private ArrayList<RemoteInput> mRemoteInputs; private @SemanticAction int mSemanticAction; private boolean mIsContextual; + private boolean mAuthenticationRequired; /** * Construct a new builder for {@link Action} object. @@ -1654,7 +1670,7 @@ public class Notification implements Parcelable * @param intent the {@link PendingIntent} to fire when users trigger this action */ public Builder(Icon icon, CharSequence title, PendingIntent intent) { - this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE); + this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE, false); } /** @@ -1665,23 +1681,25 @@ public class Notification implements Parcelable public Builder(Action action) { this(action.getIcon(), action.title, action.actionIntent, new Bundle(action.mExtras), action.getRemoteInputs(), - action.getAllowGeneratedReplies(), action.getSemanticAction()); + action.getAllowGeneratedReplies(), action.getSemanticAction(), + action.isAuthenticationRequired()); } private Builder(@Nullable Icon icon, @Nullable CharSequence title, @Nullable PendingIntent intent, @NonNull Bundle extras, @Nullable RemoteInput[] remoteInputs, boolean allowGeneratedReplies, - @SemanticAction int semanticAction) { + @SemanticAction int semanticAction, boolean authRequired) { mIcon = icon; mTitle = title; mIntent = intent; mExtras = extras; if (remoteInputs != null) { - mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length); + mRemoteInputs = new ArrayList<>(remoteInputs.length); Collections.addAll(mRemoteInputs, remoteInputs); } mAllowGeneratedReplies = allowGeneratedReplies; mSemanticAction = semanticAction; + mAuthenticationRequired = authRequired; } /** @@ -1776,6 +1794,21 @@ public class Notification implements Parcelable } /** + * Sets whether the OS should only send this action's {@link PendingIntent} on an + * unlocked device. + * + * If this is true and the device is locked when the action is invoked, the OS will + * show the keyguard and require successful authentication before invoking the intent. + * If this is false and the device is locked, the OS will decide whether authentication + * should be required. + */ + @NonNull + public Builder setAuthenticationRequired(boolean authenticationRequired) { + mAuthenticationRequired = authenticationRequired; + return this; + } + + /** * Throws an NPE if we are building a contextual action missing one of the fields * necessary to display the action. */ @@ -1827,7 +1860,8 @@ public class Notification implements Parcelable RemoteInput[] textInputsArr = textInputs.isEmpty() ? null : textInputs.toArray(new RemoteInput[textInputs.size()]); return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr, - mAllowGeneratedReplies, mSemanticAction, mIsContextual); + mAllowGeneratedReplies, mSemanticAction, mIsContextual, + mAuthenticationRequired); } } @@ -1841,7 +1875,8 @@ public class Notification implements Parcelable getRemoteInputs(), getAllowGeneratedReplies(), getSemanticAction(), - isContextual()); + isContextual(), + isAuthenticationRequired()); } @Override @@ -1870,6 +1905,7 @@ public class Notification implements Parcelable out.writeInt(mAllowGeneratedReplies ? 1 : 0); out.writeInt(mSemanticAction); out.writeInt(mIsContextual ? 1 : 0); + out.writeInt(mAuthenticationRequired ? 1 : 0); } public static final @android.annotation.NonNull Parcelable.Creator<Action> CREATOR = diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index e0951bf3f4d2..109205fadf18 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -903,7 +903,7 @@ public final class UiAutomation { try { // Calling out without a lock held. screenShot = mUiAutomationConnection.takeScreenshot( - new Rect(0, 0, displaySize.x, displaySize.y), rotation); + new Rect(0, 0, displaySize.x, displaySize.y)); if (screenShot == null) { return null; } diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index ce51dba76780..70d520176ca1 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -180,7 +180,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { } @Override - public Bitmap takeScreenshot(Rect crop, int rotation) { + public Bitmap takeScreenshot(Rect crop) { synchronized (mLock) { throwIfCalledByNotTrustedUidLocked(); throwIfShutdownLocked(); @@ -190,7 +190,15 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { try { int width = crop.width(); int height = crop.height(); - return SurfaceControl.screenshot(crop, width, height, rotation); + final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(displayToken) + .setSourceCrop(crop) + .setSize(width, height) + .build(); + final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = + SurfaceControl.captureDisplay(captureArgs); + return screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 16ddcd1d0ea3..056cfc7c28f1 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -402,7 +402,7 @@ public abstract class BackupAgent extends ContextWrapper { */ public void onFullBackup(FullBackupDataOutput data) throws IOException { FullBackup.BackupScheme backupScheme = FullBackup.getBackupScheme(this); - if (!backupScheme.isFullBackupContentEnabled()) { + if (!isDeviceToDeviceMigration() && !backupScheme.isFullBackupContentEnabled()) { return; } @@ -430,24 +430,18 @@ public abstract class BackupAgent extends ContextWrapper { final Context ceContext = createCredentialProtectedStorageContext(); final String rootDir = ceContext.getDataDir().getCanonicalPath(); final String filesDir = ceContext.getFilesDir().getCanonicalPath(); - final String noBackupDir = ceContext.getNoBackupFilesDir().getCanonicalPath(); final String databaseDir = ceContext.getDatabasePath("foo").getParentFile() .getCanonicalPath(); final String sharedPrefsDir = ceContext.getSharedPreferencesPath("foo").getParentFile() .getCanonicalPath(); - final String cacheDir = ceContext.getCacheDir().getCanonicalPath(); - final String codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath(); final Context deContext = createDeviceProtectedStorageContext(); final String deviceRootDir = deContext.getDataDir().getCanonicalPath(); final String deviceFilesDir = deContext.getFilesDir().getCanonicalPath(); - final String deviceNoBackupDir = deContext.getNoBackupFilesDir().getCanonicalPath(); final String deviceDatabaseDir = deContext.getDatabasePath("foo").getParentFile() .getCanonicalPath(); final String deviceSharedPrefsDir = deContext.getSharedPreferencesPath("foo") .getParentFile().getCanonicalPath(); - final String deviceCacheDir = deContext.getCacheDir().getCanonicalPath(); - final String deviceCodeCacheDir = deContext.getCodeCacheDir().getCanonicalPath(); final String libDir = (appInfo.nativeLibraryDir != null) ? new File(appInfo.nativeLibraryDir).getCanonicalPath() @@ -460,33 +454,36 @@ public abstract class BackupAgent extends ContextWrapper { // Add the directories we always exclude. traversalExcludeSet.add(filesDir); - traversalExcludeSet.add(noBackupDir); traversalExcludeSet.add(databaseDir); traversalExcludeSet.add(sharedPrefsDir); - traversalExcludeSet.add(cacheDir); - traversalExcludeSet.add(codeCacheDir); traversalExcludeSet.add(deviceFilesDir); - traversalExcludeSet.add(deviceNoBackupDir); traversalExcludeSet.add(deviceDatabaseDir); traversalExcludeSet.add(deviceSharedPrefsDir); - traversalExcludeSet.add(deviceCacheDir); - traversalExcludeSet.add(deviceCodeCacheDir); if (libDir != null) { traversalExcludeSet.add(libDir); } + Set<String> extraExcludedDirs = getExtraExcludeDirsIfAny(ceContext); + Set<String> extraExcludedDeviceDirs = getExtraExcludeDirsIfAny(deContext); + traversalExcludeSet.addAll(extraExcludedDirs); + traversalExcludeSet.addAll(extraExcludedDeviceDirs); + // Root dir first. applyXmlFiltersAndDoFullBackupForDomain( packageName, FullBackup.ROOT_TREE_TOKEN, manifestIncludeMap, manifestExcludeSet, traversalExcludeSet, data); traversalExcludeSet.add(rootDir); + // Exclude the extra directories anyway, since we've already covered them if it was needed. + traversalExcludeSet.addAll(extraExcludedDirs); applyXmlFiltersAndDoFullBackupForDomain( packageName, FullBackup.DEVICE_ROOT_TREE_TOKEN, manifestIncludeMap, manifestExcludeSet, traversalExcludeSet, data); traversalExcludeSet.add(deviceRootDir); + // Exclude the extra directories anyway, since we've already covered them if it was needed. + traversalExcludeSet.addAll(extraExcludedDeviceDirs); // Data dir next. traversalExcludeSet.remove(filesDir); @@ -545,11 +542,28 @@ public abstract class BackupAgent extends ContextWrapper { } } + private Set<String> getExtraExcludeDirsIfAny(Context context) throws IOException { + if (isDeviceToDeviceMigration()) { + return Collections.emptySet(); + } + + // If this is not a migration, also exclude no-backup and cache dirs. + Set<String> excludedDirs = new HashSet<>(); + excludedDirs.add(context.getCacheDir().getCanonicalPath()); + excludedDirs.add(context.getCodeCacheDir().getCanonicalPath()); + excludedDirs.add(context.getNoBackupFilesDir().getCanonicalPath()); + return Collections.unmodifiableSet(excludedDirs); + } + + private boolean isDeviceToDeviceMigration() { + return mOperationType == OperationType.MIGRATION; + } + /** @hide */ @VisibleForTesting public IncludeExcludeRules getIncludeExcludeRules(FullBackup.BackupScheme backupScheme) throws IOException, XmlPullParserException { - if (mOperationType == OperationType.MIGRATION) { + if (isDeviceToDeviceMigration()) { return IncludeExcludeRules.emptyRules(); } @@ -892,6 +906,11 @@ public abstract class BackupAgent extends ContextWrapper { } private boolean isFileEligibleForRestore(File destination) throws IOException { + if (isDeviceToDeviceMigration()) { + // Everything is eligible for device-to-device migration. + return true; + } + FullBackup.BackupScheme bs = FullBackup.getBackupScheme(this); if (!bs.isFullBackupContentEnabled()) { if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) { diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index bd1eea51f8af..cef6ab094177 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -155,10 +155,6 @@ public abstract class SliceProvider extends ContentProvider { /** * @hide */ - public static final String EXTRA_PROVIDER_PKG = "provider_pkg"; - /** - * @hide - */ public static final String EXTRA_RESULT = "result"; private static final boolean DEBUG = false; @@ -519,7 +515,6 @@ public abstract class SliceProvider extends ContentProvider { com.android.internal.R.string.config_slicePermissionComponent))); intent.putExtra(EXTRA_BIND_URI, sliceUri); intent.putExtra(EXTRA_PKG, callingPackage); - intent.putExtra(EXTRA_PROVIDER_PKG, context.getPackageName()); // Unique pending intent. intent.setData(sliceUri.buildUpon().appendQueryParameter("package", callingPackage) .build()); diff --git a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java index 236b0064763e..cc0af3f97e49 100644 --- a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java +++ b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java @@ -91,11 +91,13 @@ public final class TimeZoneCapabilities implements Parcelable { private final @UserIdInt int mUserId; private final @CapabilityState int mConfigureAutoDetectionEnabled; + private final @CapabilityState int mConfigureGeoDetectionEnabled; private final @CapabilityState int mSuggestManualTimeZone; private TimeZoneCapabilities(@NonNull Builder builder) { this.mUserId = builder.mUserId; this.mConfigureAutoDetectionEnabled = builder.mConfigureAutoDetectionEnabled; + this.mConfigureGeoDetectionEnabled = builder.mConfigureGeoDetectionEnabled; this.mSuggestManualTimeZone = builder.mSuggestManualTimeZone; } @@ -103,6 +105,7 @@ public final class TimeZoneCapabilities implements Parcelable { private static TimeZoneCapabilities createFromParcel(Parcel in) { return new TimeZoneCapabilities.Builder(in.readInt()) .setConfigureAutoDetectionEnabled(in.readInt()) + .setConfigureGeoDetectionEnabled(in.readInt()) .setSuggestManualTimeZone(in.readInt()) .build(); } @@ -111,6 +114,7 @@ public final class TimeZoneCapabilities implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mUserId); dest.writeInt(mConfigureAutoDetectionEnabled); + dest.writeInt(mConfigureGeoDetectionEnabled); dest.writeInt(mSuggestManualTimeZone); } @@ -120,8 +124,8 @@ public final class TimeZoneCapabilities implements Parcelable { } /** - * Returns the user's capability state for controlling automatic time zone detection via - * {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link + * Returns the user's capability state for controlling whether automatic time zone detection is + * enabled via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link * TimeZoneConfiguration#isAutoDetectionEnabled()}. */ @CapabilityState @@ -130,6 +134,16 @@ public final class TimeZoneCapabilities implements Parcelable { } /** + * Returns the user's capability state for controlling whether geolocation can be used to detect + * time zone via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link + * TimeZoneConfiguration#isGeoDetectionEnabled()}. + */ + @CapabilityState + public int getConfigureGeoDetectionEnabled() { + return mConfigureGeoDetectionEnabled; + } + + /** * Returns the user's capability state for manually setting the time zone on a device via * {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}. * @@ -157,12 +171,16 @@ public final class TimeZoneCapabilities implements Parcelable { TimeZoneCapabilities that = (TimeZoneCapabilities) o; return mUserId == that.mUserId && mConfigureAutoDetectionEnabled == that.mConfigureAutoDetectionEnabled + && mConfigureGeoDetectionEnabled == that.mConfigureGeoDetectionEnabled && mSuggestManualTimeZone == that.mSuggestManualTimeZone; } @Override public int hashCode() { - return Objects.hash(mUserId, mConfigureAutoDetectionEnabled, mSuggestManualTimeZone); + return Objects.hash(mUserId, + mConfigureAutoDetectionEnabled, + mConfigureGeoDetectionEnabled, + mSuggestManualTimeZone); } @Override @@ -170,6 +188,7 @@ public final class TimeZoneCapabilities implements Parcelable { return "TimeZoneDetectorCapabilities{" + "mUserId=" + mUserId + ", mConfigureAutomaticDetectionEnabled=" + mConfigureAutoDetectionEnabled + + ", mConfigureGeoDetectionEnabled=" + mConfigureGeoDetectionEnabled + ", mSuggestManualTimeZone=" + mSuggestManualTimeZone + '}'; } @@ -179,6 +198,7 @@ public final class TimeZoneCapabilities implements Parcelable { private final @UserIdInt int mUserId; private @CapabilityState int mConfigureAutoDetectionEnabled; + private @CapabilityState int mConfigureGeoDetectionEnabled; private @CapabilityState int mSuggestManualTimeZone; /** @@ -194,6 +214,12 @@ public final class TimeZoneCapabilities implements Parcelable { return this; } + /** Sets the state for the geolocation time zone detection enabled config. */ + public Builder setConfigureGeoDetectionEnabled(@CapabilityState int value) { + this.mConfigureGeoDetectionEnabled = value; + return this; + } + /** Sets the state for the suggestManualTimeZone action. */ public Builder setSuggestManualTimeZone(@CapabilityState int value) { this.mSuggestManualTimeZone = value; @@ -204,6 +230,7 @@ public final class TimeZoneCapabilities implements Parcelable { @NonNull public TimeZoneCapabilities build() { verifyCapabilitySet(mConfigureAutoDetectionEnabled, "configureAutoDetectionEnabled"); + verifyCapabilitySet(mConfigureGeoDetectionEnabled, "configureGeoDetectionEnabled"); verifyCapabilitySet(mSuggestManualTimeZone, "suggestManualTimeZone"); return new TimeZoneCapabilities(this); } diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java index 047d3493d5dd..6f84ee22a985 100644 --- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java +++ b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java @@ -67,6 +67,10 @@ public final class TimeZoneConfiguration implements Parcelable { @Property public static final String PROPERTY_AUTO_DETECTION_ENABLED = "autoDetectionEnabled"; + /** See {@link TimeZoneConfiguration#isGeoDetectionEnabled()} for details. */ + @Property + public static final String PROPERTY_GEO_DETECTION_ENABLED = "geoDetectionEnabled"; + private final Bundle mBundle; private TimeZoneConfiguration(Builder builder) { @@ -86,7 +90,8 @@ public final class TimeZoneConfiguration implements Parcelable { /** Returns {@code true} if all known properties are set. */ public boolean isComplete() { - return hasProperty(PROPERTY_AUTO_DETECTION_ENABLED); + return hasProperty(PROPERTY_AUTO_DETECTION_ENABLED) + && hasProperty(PROPERTY_GEO_DETECTION_ENABLED); } /** Returns true if the specified property is set. */ @@ -108,6 +113,28 @@ public final class TimeZoneConfiguration implements Parcelable { return mBundle.getBoolean(PROPERTY_AUTO_DETECTION_ENABLED); } + /** + * Returns the value of the {@link #PROPERTY_GEO_DETECTION_ENABLED} property. This + * controls whether a device can use location to determine time zone. Only used when + * {@link #isAutoDetectionEnabled()} is true. + * + * @throws IllegalStateException if the field has not been set + */ + public boolean isGeoDetectionEnabled() { + if (!mBundle.containsKey(PROPERTY_GEO_DETECTION_ENABLED)) { + throw new IllegalStateException(PROPERTY_GEO_DETECTION_ENABLED + " is not set"); + } + return mBundle.getBoolean(PROPERTY_GEO_DETECTION_ENABLED); + } + + /** + * Convenience method to merge this with another. The argument configuration properties have + * precedence. + */ + public TimeZoneConfiguration with(TimeZoneConfiguration other) { + return new Builder(this).mergeProperties(other).build(); + } + @Override public int describeContents() { return 0; @@ -174,6 +201,12 @@ public final class TimeZoneConfiguration implements Parcelable { return this; } + /** Sets the desired state of the geolocation time zone detection enabled property. */ + public Builder setGeoDetectionEnabled(boolean enabled) { + this.mBundle.putBoolean(PROPERTY_GEO_DETECTION_ENABLED, enabled); + return this; + } + /** Returns the {@link TimeZoneConfiguration}. */ @NonNull public TimeZoneConfiguration build() { diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index 3522b1b8aff5..0e6a0637d801 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -199,7 +199,7 @@ public final class UsageEvents implements Parcelable { public static final int NOTIFICATION_INTERRUPTION = 12; /** - * A Slice was pinned by the default launcher or the default assistant. + * A Slice was pinned by the default assistant. * @hide */ @SystemApi diff --git a/core/java/android/content/LocusId.java b/core/java/android/content/LocusId.java index 283cea00b192..98e71f07407e 100644 --- a/core/java/android/content/LocusId.java +++ b/core/java/android/content/LocusId.java @@ -33,7 +33,7 @@ import java.io.PrintWriter; * by the Android System to correlate state between different subsystems such as content capture, * shortcuts, and notifications. * - * <p>For example, if your app provides an activiy representing a chat between 2 users + * <p>For example, if your app provides an activity representing a chat between 2 users * (say {@code A} and {@code B}, this chat state could be represented by: * * <pre><code> diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 7234eb1d81cd..cd26079a7bac 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -503,6 +503,10 @@ public class NetworkTemplate implements Parcelable { for (final int ratType : ratTypes) { collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); } + // Add NETWORK_TYPE_5G_NSA to the returned list since 5G NSA is a virtual RAT type and + // it is not in TelephonyManager#NETWORK_TYPE_* constants. + // See {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. + collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(NETWORK_TYPE_5G_NSA)); // Ensure that unknown type is returned. collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); return toIntArray(collapsedRatTypes); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 1050c7f8b4f4..8e865e7ab313 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -1012,10 +1012,16 @@ public class Build { /** * Q. - * <p> - * <em>Why? Why, to give you a taste of your future, a preview of things - * to come. Con permiso, Capitan. The hall is rented, the orchestra - * engaged. It's now time to see if you can dance.</em> + * + * <p>Applications targeting this or a later release will get these new changes in behavior. + * For more information about this release, see the + * <a href="/about/versions/10">Android 10 overview</a>.</p> + * <ul> + * <li><a href="/about/versions/10/behavior-changes-all">Behavior changes: all apps</a></li> + * <li><a href="/about/versions/10/behavior-changes-10">Behavior changes: apps targeting API + * 29+</a></li> + * </ul> + * */ public static final int Q = 29; diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 0cce19222d27..8f8d451bbe8e 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -287,8 +287,8 @@ interface INetworkManagementService /** * Control network activity of a UID over interfaces with a quota limit. */ - void setUidMeteredNetworkBlacklist(int uid, boolean enable); - void setUidMeteredNetworkWhitelist(int uid, boolean enable); + void setUidMeteredNetworkDenylist(int uid, boolean enable); + void setUidMeteredNetworkAllowlist(int uid, boolean enable); boolean setDataSaverModeEnabled(boolean enable); void setUidCleartextNetworkPolicy(int uid, int policy); diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java index 3d3759e695e0..f14f66b07630 100644 --- a/core/java/android/os/Parcelable.java +++ b/core/java/android/os/Parcelable.java @@ -161,6 +161,7 @@ public interface Parcelable { * @return true if this parcelable is stable. * @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) default @Stability int getStability() { return PARCELABLE_STABILITY_LOCAL; } diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java index fd68c2b9b5fd..26f3af0c68bb 100644 --- a/core/java/android/os/SystemClock.java +++ b/core/java/android/os/SystemClock.java @@ -178,6 +178,15 @@ public final class SystemClock { native public static long uptimeMillis(); /** + * Returns nanoseconds since boot, not counting time spent in deep sleep. + * + * @return nanoseconds of non-sleep uptime since boot. + * @hide + */ + @CriticalNative + public static native long uptimeNanos(); + + /** * Return {@link Clock} that starts at system boot, not counting time spent * in deep sleep. * diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java index 8ad35e7eb37d..e2e61406ba95 100644 --- a/core/java/android/permission/PermissionControllerService.java +++ b/core/java/android/permission/PermissionControllerService.java @@ -35,6 +35,8 @@ import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.Service; import android.app.admin.DevicePolicyManager.PermissionGrantState; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -83,6 +85,15 @@ public abstract class PermissionControllerService extends Service { public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService"; /** + * A ChangeId indicating that this device supports camera and mic indicators. Will be "false" + * if present, because the CompatChanges#isChangeEnabled method returns true if the change id + * is not present. + */ + @ChangeId + @Disabled + private static final long CAMERA_MIC_INDICATORS_NOT_PRESENT = 162547999L; + + /** * Revoke a set of runtime permissions for various apps. * * @param requests The permissions to revoke as {@code Map<packageName, List<permission>>} diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 0c190719af57..b9d27e923615 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -25,6 +25,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.IActivityManager; @@ -637,24 +638,25 @@ public final class PermissionManager { private static final class PackageNamePermissionQuery { final String permName; final String pkgName; - final int uid; + final int userId; - PackageNamePermissionQuery(@Nullable String permName, @Nullable String pkgName, int uid) { + PackageNamePermissionQuery(@Nullable String permName, @Nullable String pkgName, + @UserIdInt int userId) { this.permName = permName; this.pkgName = pkgName; - this.uid = uid; + this.userId = userId; } @Override public String toString() { return String.format( - "PackageNamePermissionQuery(pkgName=\"%s\", permName=\"%s, uid=%s\")", - pkgName, permName, uid); + "PackageNamePermissionQuery(pkgName=\"%s\", permName=\"%s, userId=%s\")", + pkgName, permName, userId); } @Override public int hashCode() { - return Objects.hash(permName, pkgName, uid); + return Objects.hash(permName, pkgName, userId); } @Override @@ -670,16 +672,16 @@ public final class PermissionManager { } return Objects.equals(permName, other.permName) && Objects.equals(pkgName, other.pkgName) - && uid == other.uid; + && userId == other.userId; } } /* @hide */ private static int checkPackageNamePermissionUncached( - String permName, String pkgName, int uid) { + String permName, String pkgName, @UserIdInt int userId) { try { return ActivityThread.getPermissionManager().checkPermission( - permName, pkgName, uid); + permName, pkgName, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -693,7 +695,7 @@ public final class PermissionManager { @Override protected Integer recompute(PackageNamePermissionQuery query) { return checkPackageNamePermissionUncached( - query.permName, query.pkgName, query.uid); + query.permName, query.pkgName, query.userId); } }; @@ -702,9 +704,10 @@ public final class PermissionManager { * * @hide */ - public static int checkPackageNamePermission(String permName, String pkgName, int uid) { + public static int checkPackageNamePermission(String permName, String pkgName, + @UserIdInt int userId) { return sPackageNamePermissionCache.query( - new PackageNamePermissionQuery(permName, pkgName, uid)); + new PackageNamePermissionQuery(permName, pkgName, userId)); } /** diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java index c1998c6009cf..82f60366a814 100644 --- a/core/java/android/view/ImeInsetsSourceConsumer.java +++ b/core/java/android/view/ImeInsetsSourceConsumer.java @@ -69,7 +69,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { } public void onServedEditorChanged(EditorInfo info) { - if (isDummyOrEmptyEditor(info)) { + if (isFallbackOrEmptyEditor(info)) { mShowOnNextImeRender = false; } mFocusedEditor = info; @@ -167,15 +167,15 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { } } - private boolean isDummyOrEmptyEditor(EditorInfo info) { - // TODO(b/123044812): Handle dummy input gracefully in IME Insets API + private boolean isFallbackOrEmptyEditor(EditorInfo info) { + // TODO(b/123044812): Handle fallback input gracefully in IME Insets API return info == null || (info.fieldId <= 0 && info.inputType <= 0); } private boolean isServedEditorRendered() { if (mFocusedEditor == null || mPreRenderedEditor == null - || isDummyOrEmptyEditor(mFocusedEditor) - || isDummyOrEmptyEditor(mPreRenderedEditor)) { + || isFallbackOrEmptyEditor(mFocusedEditor) + || isFallbackOrEmptyEditor(mPreRenderedEditor)) { // No view is focused or ready. return false; } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 2ce993dfedca..6ef086b55c41 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -22,8 +22,6 @@ import static android.graphics.Matrix.MSKEW_X; import static android.graphics.Matrix.MSKEW_Y; import static android.graphics.Matrix.MTRANS_X; import static android.graphics.Matrix.MTRANS_Y; -import static android.view.Surface.ROTATION_270; -import static android.view.Surface.ROTATION_90; import static android.view.SurfaceControlProto.HASH_CODE; import static android.view.SurfaceControlProto.NAME; @@ -590,6 +588,26 @@ public final class SurfaceControl implements Parcelable { public boolean containsSecureLayers() { return mContainsSecureLayers; } + + /** + * Copy content of ScreenshotHardwareBuffer into a hardware bitmap and return it. + * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap + * into + * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)} + * + * CAVEAT: This can be extremely slow; avoid use unless absolutely necessary; prefer to + * directly + * use the {@link HardwareBuffer} directly. + * + * @return Bitmap generated from the {@link HardwareBuffer} + */ + public Bitmap asBitmap() { + if (mHardwareBuffer == null) { + Log.w(TAG, "Failed to take screenshot. Null screenshot object"); + return null; + } + return Bitmap.wrapHardwareBuffer(mHardwareBuffer, mColorSpace); + } } /** @@ -597,7 +615,7 @@ public final class SurfaceControl implements Parcelable { * are shared between {@link DisplayCaptureArgs} and {@link LayerCaptureArgs} * @hide */ - public abstract static class CaptureArgs { + private abstract static class CaptureArgs { private final int mPixelFormat; private final Rect mSourceCrop = new Rect(); private final float mFrameScale; @@ -615,7 +633,7 @@ public final class SurfaceControl implements Parcelable { * * @param <T> A builder that extends {@link Builder} */ - public abstract static class Builder<T extends Builder<T>> { + abstract static class Builder<T extends Builder<T>> { private int mPixelFormat = PixelFormat.RGBA_8888; private final Rect mSourceCrop = new Rect(); private float mFrameScale = 1; @@ -675,7 +693,6 @@ public final class SurfaceControl implements Parcelable { private final int mWidth; private final int mHeight; private final boolean mUseIdentityTransform; - private final int mRotation; private DisplayCaptureArgs(Builder builder) { super(builder); @@ -683,7 +700,6 @@ public final class SurfaceControl implements Parcelable { mWidth = builder.mWidth; mHeight = builder.mHeight; mUseIdentityTransform = builder.mUseIdentityTransform; - mRotation = builder.mRotation; } /** @@ -694,7 +710,6 @@ public final class SurfaceControl implements Parcelable { private int mWidth; private int mHeight; private boolean mUseIdentityTransform; - private @Surface.Rotation int mRotation = Surface.ROTATION_0; /** * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder @@ -736,26 +751,16 @@ public final class SurfaceControl implements Parcelable { } /** - * Replace whatever transformation (rotation, scaling, translation) the surface - * layers are currently using with the identity transformation while taking the - * screenshot. + * Replace the rotation transform of the display with the identity transformation while + * taking the screenshot. This ensures the screenshot is taken in the ROTATION_0 + * orientation. Set this value to false if the screenshot should be taken in the + * current screen orientation. */ public Builder setUseIdentityTransform(boolean useIdentityTransform) { mUseIdentityTransform = useIdentityTransform; return this; } - /** - * Apply a custom clockwise rotation to the screenshot, i.e. - * Surface.ROTATION_0,90,180,270. SurfaceFlinger will always take screenshots in its - * native portrait orientation by default, so this is useful for returning screenshots - * that are independent of device orientation. - */ - public Builder setRotation(@Surface.Rotation int rotation) { - mRotation = rotation; - return this; - } - @Override Builder getThis() { return this; @@ -2221,130 +2226,16 @@ public final class SurfaceControl implements Parcelable { } /** - * @see SurfaceControl#screenshot(Rect, int, int, boolean, int)} - * @hide - */ - @UnsupportedAppUsage - public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) { - return screenshot(sourceCrop, width, height, false, rotation); - } - - /** - * Copy the current screen contents into a hardware bitmap and return it. - * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap into - * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)} + * Captures all the surfaces in a display and returns a {@link ScreenshotHardwareBuffer} with + * the content. * - * CAVEAT: Versions of screenshot that return a {@link Bitmap} can be extremely slow; avoid use - * unless absolutely necessary; prefer the versions that use a {@link HardwareBuffer} such as - * {@link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}. - * - * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)} * @hide */ - @UnsupportedAppUsage - public static Bitmap screenshot(Rect sourceCrop, int width, int height, - boolean useIdentityTransform, int rotation) { - // TODO: should take the display as a parameter - final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); - if (displayToken == null) { - Log.w(TAG, "Failed to take screenshot because internal display is disconnected"); - return null; - } - - if (rotation == ROTATION_90 || rotation == ROTATION_270) { - rotation = (rotation == ROTATION_90) ? ROTATION_270 : ROTATION_90; - } - - SurfaceControl.rotateCropForSF(sourceCrop, rotation); - final ScreenshotHardwareBuffer buffer = screenshotToBuffer(displayToken, sourceCrop, width, - height, useIdentityTransform, rotation); - - if (buffer == null) { - Log.w(TAG, "Failed to take screenshot"); - return null; - } - return Bitmap.wrapHardwareBuffer(buffer.getHardwareBuffer(), buffer.getColorSpace()); - } - - /** - * Captures all the surfaces in a display and returns a {@link HardwareBuffer} with the content. - * - * @param display The display to take the screenshot of. - * @param sourceCrop The portion of the screen to capture into the Bitmap; caller may - * pass in 'new Rect()' if no cropping is desired. - * @param width The desired width of the returned bitmap; the raw screen will be - * scaled down to this size; caller may pass in 0 if no scaling is - * desired. - * @param height The desired height of the returned bitmap; the raw screen will - * be scaled down to this size; caller may pass in 0 if no scaling - * is desired. - * @param useIdentityTransform Replace whatever transformation (rotation, scaling, translation) - * the surface layers are currently using with the identity - * transformation while taking the screenshot. - * @param rotation Apply a custom clockwise rotation to the screenshot, i.e. - * Surface.ROTATION_0,90,180,270. SurfaceFlinger will always take - * screenshots in its native portrait orientation by default, so - * this is useful for returning screenshots that are independent of - * device orientation. - * @return Returns a HardwareBuffer that contains the captured content. - * @hide - */ - public static ScreenshotHardwareBuffer screenshotToBuffer(IBinder display, Rect sourceCrop, - int width, int height, boolean useIdentityTransform, int rotation) { - if (display == null) { - throw new IllegalArgumentException("displayToken must not be null"); - } - - DisplayCaptureArgs captureArgs = new DisplayCaptureArgs.Builder(display) - .setSourceCrop(sourceCrop) - .setSize(width, height) - .setUseIdentityTransform(useIdentityTransform) - .setRotation(rotation) - .build(); - + public static ScreenshotHardwareBuffer captureDisplay(DisplayCaptureArgs captureArgs) { return nativeCaptureDisplay(captureArgs); } /** - * Like screenshotToBuffer, but if the caller is AID_SYSTEM, allows - * for the capture of secure layers. This is used for the screen rotation - * animation where the system server takes screenshots but does - * not persist them or allow them to leave the server. However in other - * cases in the system server, we mostly want to omit secure layers - * like when we take a screenshot on behalf of the assistant. - * - * @hide - */ - public static ScreenshotHardwareBuffer screenshotToBufferWithSecureLayersUnsafe(IBinder display, - Rect sourceCrop, int width, int height, boolean useIdentityTransform, - int rotation) { - if (display == null) { - throw new IllegalArgumentException("displayToken must not be null"); - } - - DisplayCaptureArgs captureArgs = new DisplayCaptureArgs.Builder(display) - .setSourceCrop(sourceCrop) - .setSize(width, height) - .setUseIdentityTransform(useIdentityTransform) - .setRotation(rotation) - .setCaptureSecureLayers(true) - .build(); - - return nativeCaptureDisplay(captureArgs); - } - - private static void rotateCropForSF(Rect crop, int rot) { - if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { - int tmp = crop.top; - crop.top = crop.left; - crop.left = tmp; - tmp = crop.right; - crop.right = crop.bottom; - crop.bottom = tmp; - } - } - - /** * Captures a layer and its children and returns a {@link HardwareBuffer} with the content. * * @param layer The root layer to capture. diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl index e814ec649087..eb67191e5f54 100644 --- a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl +++ b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl @@ -29,7 +29,7 @@ import android.view.accessibility.IWindowMagnificationConnectionCallback; oneway interface IWindowMagnificationConnection { /** - * Enables window magnification on specifed display with specified center and scale. + * Enables window magnification on specified display with given center and scale and animation. * * @param displayId The logical display id. * @param scale magnification scale. @@ -41,7 +41,7 @@ oneway interface IWindowMagnificationConnection { void enableWindowMagnification(int displayId, float scale, float centerX, float centerY); /** - * Sets the scale of the window magnifier on specifed display. + * Sets the scale of the window magnifier on specified display. * * @param displayId The logical display id. * @param scale magnification scale. @@ -49,14 +49,14 @@ oneway interface IWindowMagnificationConnection { void setScale(int displayId, float scale); /** - * Disables window magnification on specifed display. + * Disables window magnification on specified display with animation. * * @param displayId The logical display id. */ void disableWindowMagnification(int displayId); /** - * Moves the window magnifier on the specifed display. + * Moves the window magnifier on the specified display. It has no effect while animating. * * @param offsetX the amount in pixels to offset the window magnifier in the X direction, in * current screen pixels. diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index d5d631ac1dc7..eef27262c699 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -54,7 +54,7 @@ public class BaseInputConnection implements InputConnection { /** @hide */ protected final InputMethodManager mIMM; final View mTargetView; - final boolean mDummyMode; + final boolean mFallbackMode; private Object[] mDefaultComposingSpans; @@ -64,14 +64,14 @@ public class BaseInputConnection implements InputConnection { BaseInputConnection(InputMethodManager mgr, boolean fullEditor) { mIMM = mgr; mTargetView = null; - mDummyMode = !fullEditor; + mFallbackMode = !fullEditor; } public BaseInputConnection(View targetView, boolean fullEditor) { mIMM = (InputMethodManager)targetView.getContext().getSystemService( Context.INPUT_METHOD_SERVICE); mTargetView = targetView; - mDummyMode = !fullEditor; + mFallbackMode = !fullEditor; } public static final void removeComposingSpans(Spannable text) { @@ -189,7 +189,7 @@ public class BaseInputConnection implements InputConnection { /** * Default implementation replaces any existing composing text with - * the given text. In addition, only if dummy mode, a key event is + * the given text. In addition, only if fallback mode, a key event is * sent for the new text and the current editable buffer cleared. */ public boolean commitText(CharSequence text, int newCursorPosition) { @@ -445,7 +445,7 @@ public class BaseInputConnection implements InputConnection { /** * The default implementation removes the composing state from the - * current editable text. In addition, only if dummy mode, a key event is + * current editable text. In addition, only if fallback mode, a key event is * sent for the new text and the current editable buffer cleared. */ public boolean finishComposingText() { @@ -454,7 +454,7 @@ public class BaseInputConnection implements InputConnection { if (content != null) { beginBatchEdit(); removeComposingSpans(content); - // Note: sendCurrentText does nothing unless mDummyMode is set + // Note: sendCurrentText does nothing unless mFallbackMode is set sendCurrentText(); endBatchEdit(); } @@ -464,10 +464,10 @@ public class BaseInputConnection implements InputConnection { /** * The default implementation uses TextUtils.getCapsMode to get the * cursor caps mode for the current selection position in the editable - * text, unless in dummy mode in which case 0 is always returned. + * text, unless in fallback mode in which case 0 is always returned. */ public int getCursorCapsMode(int reqModes) { - if (mDummyMode) return 0; + if (mFallbackMode) return 0; final Editable content = getEditable(); if (content == null) return 0; @@ -664,7 +664,7 @@ public class BaseInputConnection implements InputConnection { content.setSpan(COMPOSING, a, b, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING); - // Note: sendCurrentText does nothing unless mDummyMode is set + // Note: sendCurrentText does nothing unless mFallbackMode is set sendCurrentText(); endBatchEdit(); } @@ -715,7 +715,7 @@ public class BaseInputConnection implements InputConnection { } private void sendCurrentText() { - if (!mDummyMode) { + if (!mFallbackMode) { return; } diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java index fed3dbf8f49c..00086587819f 100644 --- a/core/java/android/view/textclassifier/TextClassificationSession.java +++ b/core/java/android/view/textclassifier/TextClassificationSession.java @@ -20,9 +20,11 @@ import android.annotation.NonNull; import android.annotation.WorkerThread; import android.view.textclassifier.SelectionEvent.InvocationMethod; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import java.util.Objects; +import java.util.function.Supplier; import sun.misc.Cleaner; @@ -40,6 +42,9 @@ final class TextClassificationSession implements TextClassifier { private final TextClassificationContext mClassificationContext; private final Cleaner mCleaner; + private final Object mLock = new Object(); + + @GuardedBy("mLock") private boolean mDestroyed; TextClassificationSession(TextClassificationContext context, TextClassifier delegate) { @@ -54,8 +59,7 @@ final class TextClassificationSession implements TextClassifier { @Override public TextSelection suggestSelection(TextSelection.Request request) { - checkDestroyed(); - return mDelegate.suggestSelection(request); + return checkDestroyedAndRun(() -> mDelegate.suggestSelection(request)); } private void initializeRemoteSession() { @@ -67,77 +71,97 @@ final class TextClassificationSession implements TextClassifier { @Override public TextClassification classifyText(TextClassification.Request request) { - checkDestroyed(); - return mDelegate.classifyText(request); + return checkDestroyedAndRun(() -> mDelegate.classifyText(request)); } @Override public TextLinks generateLinks(TextLinks.Request request) { - checkDestroyed(); - return mDelegate.generateLinks(request); + return checkDestroyedAndRun(() -> mDelegate.generateLinks(request)); } @Override public ConversationActions suggestConversationActions(ConversationActions.Request request) { - checkDestroyed(); - return mDelegate.suggestConversationActions(request); + return checkDestroyedAndRun(() -> mDelegate.suggestConversationActions(request)); } @Override public TextLanguage detectLanguage(TextLanguage.Request request) { - checkDestroyed(); - return mDelegate.detectLanguage(request); + return checkDestroyedAndRun(() -> mDelegate.detectLanguage(request)); } @Override public int getMaxGenerateLinksTextLength() { - checkDestroyed(); - return mDelegate.getMaxGenerateLinksTextLength(); + return checkDestroyedAndRun(mDelegate::getMaxGenerateLinksTextLength); } @Override public void onSelectionEvent(SelectionEvent event) { - try { - if (mEventHelper.sanitizeEvent(event)) { - mDelegate.onSelectionEvent(event); + checkDestroyedAndRun(() -> { + try { + if (mEventHelper.sanitizeEvent(event)) { + mDelegate.onSelectionEvent(event); + } + } catch (Exception e) { + // Avoid crashing for event reporting. + Log.e(LOG_TAG, "Error reporting text classifier selection event", e); } - } catch (Exception e) { - // Avoid crashing for event reporting. - Log.e(LOG_TAG, "Error reporting text classifier selection event", e); - } + return null; + }); } @Override public void onTextClassifierEvent(TextClassifierEvent event) { - try { - event.mHiddenTempSessionId = mSessionId; - mDelegate.onTextClassifierEvent(event); - } catch (Exception e) { - // Avoid crashing for event reporting. - Log.e(LOG_TAG, "Error reporting text classifier event", e); - } + checkDestroyedAndRun(() -> { + try { + event.mHiddenTempSessionId = mSessionId; + mDelegate.onTextClassifierEvent(event); + } catch (Exception e) { + // Avoid crashing for event reporting. + Log.e(LOG_TAG, "Error reporting text classifier event", e); + } + return null; + }); } @Override public void destroy() { - mCleaner.clean(); - mDestroyed = true; + synchronized (mLock) { + if (!mDestroyed) { + mCleaner.clean(); + mDestroyed = true; + } + } } @Override public boolean isDestroyed() { - return mDestroyed; + synchronized (mLock) { + return mDestroyed; + } } /** - * @throws IllegalStateException if this TextClassification session has been destroyed. + * Check whether the TextClassification Session was destroyed before and after the actual API + * invocation, and return response if not. + * + * @param responseSupplier a Supplier that represents a TextClassifier call + * @return the response of the TextClassifier call + * @throws IllegalStateException if this TextClassification session was destroyed before the + * call returned * @see #isDestroyed() * @see #destroy() */ - private void checkDestroyed() { - if (mDestroyed) { - throw new IllegalStateException("This TextClassification session has been destroyed"); + private <T> T checkDestroyedAndRun(Supplier<T> responseSupplier) { + if (!isDestroyed()) { + T response = responseSupplier.get(); + synchronized (mLock) { + if (!mDestroyed) { + return response; + } + } } + throw new IllegalStateException( + "This TextClassification session has been destroyed"); } /** diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 7683067958d8..60f8bb7ebe6c 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -154,6 +154,10 @@ public class Editor { // Specifies whether to use the magnifier when pressing the insertion or selection handles. private static final boolean FLAG_USE_MAGNIFIER = true; + // Specifies how far to make the cursor start float when drag the cursor away from the + // beginning or end of the line. + private static final int CURSOR_START_FLOAT_DISTANCE_PX = 20; + private static final int DELAY_BEFORE_HANDLE_FADES_OUT = 4000; private static final int RECENT_CUT_COPY_DURATION_MS = 15 * 1000; // 15 seconds in millis @@ -289,6 +293,9 @@ public class Editor { private boolean mRenderCursorRegardlessTiming; private Blink mBlink; + // Whether to let magnifier draw cursor on its surface. This is for floating cursor effect. + // And it can only be true when |mNewMagnifierEnabled| is true. + private boolean mDrawCursorOnMagnifier; boolean mCursorVisible = true; boolean mSelectAllOnFocus; boolean mTextIsSelectable; @@ -890,7 +897,7 @@ public class Editor { } boolean enabled = windowSupportsHandles && mTextView.getLayout() != null; - mInsertionControllerEnabled = enabled && isCursorVisible(); + mInsertionControllerEnabled = enabled && (mDrawCursorOnMagnifier || isCursorVisible()); mSelectionControllerEnabled = enabled && mTextView.textCanBeSelected(); if (!mInsertionControllerEnabled) { @@ -5101,26 +5108,38 @@ public class Editor { final int[] textViewLocationOnScreen = new int[2]; mTextView.getLocationOnScreen(textViewLocationOnScreen); final float touchXInView = event.getRawX() - textViewLocationOnScreen[0]; - float leftBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); - float rightBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); - if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_END) ^ rtl)) { - leftBound += getHorizontal(mTextView.getLayout(), otherHandleOffset); - } else { - leftBound += mTextView.getLayout().getLineLeft(lineNumber); - } - if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_START) ^ rtl)) { - rightBound += getHorizontal(mTextView.getLayout(), otherHandleOffset); + float leftBound, rightBound; + if (mNewMagnifierEnabled) { + leftBound = 0; + rightBound = mTextView.getWidth(); + if (touchXInView < leftBound || touchXInView > rightBound) { + // The touch is too far from the current line / selection, so hide the magnifier. + return false; + } } else { - rightBound += mTextView.getLayout().getLineRight(lineNumber); - } - leftBound *= mTextViewScaleX; - rightBound *= mTextViewScaleX; - final float contentWidth = Math.round(mMagnifierAnimator.mMagnifier.getWidth() - / mMagnifierAnimator.mMagnifier.getZoom()); - if (touchXInView < leftBound - contentWidth / 2 - || touchXInView > rightBound + contentWidth / 2) { - // The touch is too far from the current line / selection, so hide the magnifier. - return false; + leftBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); + rightBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); + if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_END) + ^ rtl)) { + leftBound += getHorizontal(mTextView.getLayout(), otherHandleOffset); + } else { + leftBound += mTextView.getLayout().getLineLeft(lineNumber); + } + if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_START) + ^ rtl)) { + rightBound += getHorizontal(mTextView.getLayout(), otherHandleOffset); + } else { + rightBound += mTextView.getLayout().getLineRight(lineNumber); + } + leftBound *= mTextViewScaleX; + rightBound *= mTextViewScaleX; + final float contentWidth = Math.round(mMagnifierAnimator.mMagnifier.getWidth() + / mMagnifierAnimator.mMagnifier.getZoom()); + if (touchXInView < leftBound - contentWidth / 2 + || touchXInView > rightBound + contentWidth / 2) { + // The touch is too far from the current line / selection, so hide the magnifier. + return false; + } } final float scaledTouchXInView; @@ -5178,7 +5197,8 @@ public class Editor { final Rect magnifierRect = new Rect(magnifierTopLeft.x, magnifierTopLeft.y, magnifierTopLeft.x + mMagnifierAnimator.mMagnifier.getWidth(), magnifierTopLeft.y + mMagnifierAnimator.mMagnifier.getHeight()); - setVisible(!handleOverlapsMagnifier(HandleView.this, magnifierRect)); + setVisible(!handleOverlapsMagnifier(HandleView.this, magnifierRect) + && !mDrawCursorOnMagnifier); final HandleView otherHandle = getOtherSelectionHandle(); if (otherHandle != null) { otherHandle.setVisible(!handleOverlapsMagnifier(otherHandle, magnifierRect)); @@ -5208,7 +5228,20 @@ public class Editor { lineLeft += mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); int lineRight = (int) layout.getLineRight(line); lineRight += mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); - mMagnifierAnimator.mMagnifier.setSourceHorizontalBounds(lineLeft, lineRight); + mDrawCursorOnMagnifier = + showPosInView.x < lineLeft - CURSOR_START_FLOAT_DISTANCE_PX + || showPosInView.x > lineRight + CURSOR_START_FLOAT_DISTANCE_PX; + mMagnifierAnimator.mMagnifier.setDrawCursor( + mDrawCursorOnMagnifier, mDrawableForCursor); + boolean cursorVisible = mCursorVisible; + // Updates cursor visibility, so that the real cursor and the float cursor on + // magnifier surface won't appear at the same time. + mCursorVisible = !mDrawCursorOnMagnifier; + if (mCursorVisible && !cursorVisible) { + // When the real cursor is a drawable, hiding/showing it would change its + // bounds. So, call updateCursorPosition() to correct its position. + updateCursorPosition(); + } final int lineHeight = layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line); float zoom = mInitialZoom; @@ -5230,6 +5263,11 @@ public class Editor { if (mMagnifierAnimator != null) { mMagnifierAnimator.dismiss(); mRenderCursorRegardlessTiming = false; + mDrawCursorOnMagnifier = false; + if (!mCursorVisible) { + mCursorVisible = true; + mTextView.invalidate(); + } resumeBlink(); setVisible(true); final HandleView otherHandle = getOtherSelectionHandle(); diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index 89206fda39f3..c72eed45e794 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -149,9 +149,6 @@ public final class Magnifier { private int mLeftCutWidth = 0; // The width of the cut region on the right edge of the pixel copy source rect. private int mRightCutWidth = 0; - // The horizontal bounds of the content source in pixels, relative to the view. - private int mLeftBound = Integer.MIN_VALUE; - private int mRightBound = Integer.MAX_VALUE; // The width of the ramp region in pixels on the left & right sides of the fish-eye effect. private final int mRamp; @@ -244,18 +241,6 @@ public final class Magnifier { } /** - * Sets the horizontal bounds of the source when showing the magnifier. - * This is used for new style magnifier. e.g. limit the source bounds by the text line bounds. - * - * @param left the left of the bounds, relative to the view. - * @param right the right of the bounds, relative to the view. - */ - void setSourceHorizontalBounds(int left, int right) { - mLeftBound = left; - mRightBound = right; - } - - /** * Shows the magnifier on the screen. The method takes the coordinates of the center * of the content source going to be magnified and copied to the magnifier. The coordinates * are relative to the top left corner of the magnified view. The magnifier will be @@ -280,6 +265,14 @@ public final class Magnifier { sourceCenterY + mDefaultVerticalSourceToMagnifierOffset); } + private Drawable mCursorDrawable; + private boolean mDrawCursorEnabled; + + void setDrawCursor(boolean enabled, Drawable cursorDrawable) { + mDrawCursorEnabled = enabled; + mCursorDrawable = cursorDrawable; + } + /** * Shows the magnifier on the screen at a position that is independent from its content * position. The first two arguments represent the coordinates of the center of the @@ -309,8 +302,7 @@ public final class Magnifier { magnifierCenterX = mClampedCenterZoomCoords.x - mViewCoordinatesInSurface[0]; magnifierCenterY = mClampedCenterZoomCoords.y - mViewCoordinatesInSurface[1]; - // mLeftBound & mRightBound (typically the text line left/right) is for magnified - // content. However the PixelCopy requires the pre-magnified bounds. + // PixelCopy requires the pre-magnified bounds. // The below logic calculates the leftBound & rightBound for the pre-magnified bounds. final float rampPre = (mSourceWidth - (mSourceWidth - 2 * mRamp) / mZoom) / 2; @@ -318,7 +310,7 @@ public final class Magnifier { // Calculates the pre-zoomed left edge. // The leftEdge moves from the left of view towards to sourceCenterX, considering the // fisheye-like zooming. - final float x0 = sourceCenterX - mSourceWidth / 2; + final float x0 = sourceCenterX - mSourceWidth / 2f; final float rampX0 = x0 + mRamp; float leftEdge = 0; if (leftEdge > rampX0) { @@ -330,12 +322,12 @@ public final class Magnifier { // increase per ramp zoom (ramp / rampPre). leftEdge = x0 + rampPre - (rampX0 - leftEdge) * rampPre / mRamp; } - int leftBound = Math.min(Math.max((int) leftEdge, mLeftBound), mRightBound); + int leftBound = Math.min((int) leftEdge, mView.getWidth()); // Calculates the pre-zoomed right edge. // The rightEdge moves from the right of view towards to sourceCenterX, considering the // fisheye-like zooming. - final float x1 = sourceCenterX + mSourceWidth / 2; + final float x1 = sourceCenterX + mSourceWidth / 2f; final float rampX1 = x1 - mRamp; float rightEdge = mView.getWidth(); if (rightEdge < rampX1) { @@ -347,7 +339,7 @@ public final class Magnifier { // increase per ramp zoom (ramp / rampPre). rightEdge = x1 - rampPre + (rightEdge - rampX1) * rampPre / mRamp; } - int rightBound = Math.max(leftBound, Math.min((int) rightEdge, mRightBound)); + int rightBound = Math.max(leftBound, (int) rightEdge); // Gets the startX for new style, which should be bounded by the horizontal bounds. // Also calculates the left/right cut width for pixel copy. @@ -772,6 +764,23 @@ public final class Magnifier { } } + private void maybeDrawCursor(Canvas canvas) { + if (mDrawCursorEnabled) { + if (mCursorDrawable != null) { + mCursorDrawable.setBounds( + mSourceWidth / 2, 0, + mSourceWidth / 2 + mCursorDrawable.getIntrinsicWidth(), mSourceHeight); + mCursorDrawable.draw(canvas); + } else { + Paint paint = new Paint(); + paint.setColor(Color.BLACK); // The cursor on magnifier is by default in black. + canvas.drawRect( + new Rect(mSourceWidth / 2 - 1, 0, mSourceWidth / 2 + 1, mSourceHeight), + paint); + } + } + } + private void performPixelCopy(final int startXInSurface, final int startYInSurface, final boolean updateWindowPosition) { if (mContentCopySurface.mSurface == null || !mContentCopySurface.mSurface.isValid()) { @@ -827,8 +836,10 @@ public final class Magnifier { final Rect dstRect = new Rect(mLeftCutWidth, 0, mSourceWidth - mRightCutWidth, bitmap.getHeight()); can.drawBitmap(bitmap, null, dstRect, null); + maybeDrawCursor(can); mWindow.updateContent(newBitmap); } else { + maybeDrawCursor(new Canvas(bitmap)); mWindow.updateContent(bitmap); } } diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 201626abd820..f5bef0b006f5 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -74,6 +74,10 @@ public class BinderCallsStats implements BinderInternal.Observer { // Whether to collect all the data: cpu + exceptions + reply/request sizes. private boolean mDetailedTracking = DETAILED_TRACKING_DEFAULT; + // If set to true, indicates that all transactions for specific UIDs are being + // recorded, ignoring sampling. The UidEntry.recordAllTransactions flag is also set + // for the UIDs being tracked. + private boolean mRecordingAllTransactionsForUid; // Sampling period to control how often to track CPU usage. 1 means all calls, 100 means ~1 out // of 100 requests. private int mPeriodicSamplingInterval = PERIODIC_SAMPLING_INTERVAL_DEFAULT; @@ -178,7 +182,8 @@ public class BinderCallsStats implements BinderInternal.Observer { @Override @Nullable public CallSession callStarted(Binder binder, int code, int workSourceUid) { - if (mDeviceState == null || mDeviceState.isCharging()) { + if (!mRecordingAllTransactionsForUid + && (mDeviceState == null || mDeviceState.isCharging())) { return null; } @@ -190,7 +195,9 @@ public class BinderCallsStats implements BinderInternal.Observer { s.exceptionThrown = false; s.cpuTimeStarted = -1; s.timeStarted = -1; - if (shouldRecordDetailedData()) { + s.recordedCall = shouldRecordDetailedData(); + + if (mRecordingAllTransactionsForUid || s.recordedCall) { s.cpuTimeStarted = getThreadTimeMicro(); s.timeStarted = getElapsedRealtimeMicro(); } @@ -218,8 +225,17 @@ public class BinderCallsStats implements BinderInternal.Observer { private void processCallEnded(CallSession s, int parcelRequestSize, int parcelReplySize, int workSourceUid) { - // Non-negative time signals we need to record data for this call. - final boolean recordCall = s.cpuTimeStarted >= 0; + UidEntry uidEntry = null; + final boolean recordCall; + if (s.recordedCall) { + recordCall = true; + } else if (mRecordingAllTransactionsForUid) { + uidEntry = getUidEntry(workSourceUid); + recordCall = uidEntry.recordAllTransactions; + } else { + recordCall = false; + } + final long duration; final long latencyDuration; if (recordCall) { @@ -238,14 +254,17 @@ public class BinderCallsStats implements BinderInternal.Observer { synchronized (mLock) { // This was already checked in #callStart but check again while synchronized. - if (mDeviceState == null || mDeviceState.isCharging()) { + if (!mRecordingAllTransactionsForUid + && (mDeviceState == null || mDeviceState.isCharging())) { return; } - final UidEntry uidEntry = getUidEntry(workSourceUid); + if (uidEntry == null) { + uidEntry = getUidEntry(workSourceUid); + } + uidEntry.callCount++; uidEntry.incrementalCallCount++; - if (recordCall) { uidEntry.cpuTimeMicros += duration; uidEntry.recordedCallCount++; @@ -357,28 +376,67 @@ public class BinderCallsStats implements BinderInternal.Observer { for (int entryIdx = 0; entryIdx < uidEntriesSize; entryIdx++) { final UidEntry entry = mUidEntries.valueAt(entryIdx); for (CallStat stat : entry.getCallStatsList()) { - ExportedCallStat exported = new ExportedCallStat(); - exported.workSourceUid = entry.workSourceUid; - exported.callingUid = stat.callingUid; - exported.className = stat.binderClass.getName(); - exported.binderClass = stat.binderClass; - exported.transactionCode = stat.transactionCode; - exported.screenInteractive = stat.screenInteractive; - exported.cpuTimeMicros = stat.cpuTimeMicros; - exported.maxCpuTimeMicros = stat.maxCpuTimeMicros; - exported.latencyMicros = stat.latencyMicros; - exported.maxLatencyMicros = stat.maxLatencyMicros; - exported.recordedCallCount = stat.recordedCallCount; - exported.callCount = stat.callCount; - exported.maxRequestSizeBytes = stat.maxRequestSizeBytes; - exported.maxReplySizeBytes = stat.maxReplySizeBytes; - exported.exceptionCount = stat.exceptionCount; - resultCallStats.add(exported); + resultCallStats.add(getExportedCallStat(entry.workSourceUid, stat)); } } } // Resolve codes outside of the lock since it can be slow. + resolveBinderMethodNames(resultCallStats); + + // Debug entries added to help validate the data. + if (mAddDebugEntries && mBatteryStopwatch != null) { + resultCallStats.add(createDebugEntry("start_time_millis", mStartElapsedTime)); + resultCallStats.add(createDebugEntry("end_time_millis", SystemClock.elapsedRealtime())); + resultCallStats.add( + createDebugEntry("battery_time_millis", mBatteryStopwatch.getMillis())); + resultCallStats.add(createDebugEntry("sampling_interval", mPeriodicSamplingInterval)); + } + + return resultCallStats; + } + + /** + * This method is expensive to call. + */ + public ArrayList<ExportedCallStat> getExportedCallStats(int workSourceUid) { + ArrayList<ExportedCallStat> resultCallStats = new ArrayList<>(); + synchronized (mLock) { + final UidEntry entry = getUidEntry(workSourceUid); + for (CallStat stat : entry.getCallStatsList()) { + resultCallStats.add(getExportedCallStat(workSourceUid, stat)); + } + } + + // Resolve codes outside of the lock since it can be slow. + resolveBinderMethodNames(resultCallStats); + + return resultCallStats; + } + + private ExportedCallStat getExportedCallStat(int workSourceUid, CallStat stat) { + ExportedCallStat exported = new ExportedCallStat(); + exported.workSourceUid = workSourceUid; + exported.callingUid = stat.callingUid; + exported.className = stat.binderClass.getName(); + exported.binderClass = stat.binderClass; + exported.transactionCode = stat.transactionCode; + exported.screenInteractive = stat.screenInteractive; + exported.cpuTimeMicros = stat.cpuTimeMicros; + exported.maxCpuTimeMicros = stat.maxCpuTimeMicros; + exported.latencyMicros = stat.latencyMicros; + exported.maxLatencyMicros = stat.maxLatencyMicros; + exported.recordedCallCount = stat.recordedCallCount; + exported.callCount = stat.callCount; + exported.maxRequestSizeBytes = stat.maxRequestSizeBytes; + exported.maxReplySizeBytes = stat.maxReplySizeBytes; + exported.exceptionCount = stat.exceptionCount; + return exported; + } + + private void resolveBinderMethodNames( + ArrayList<ExportedCallStat> resultCallStats) { + // Resolve codes outside of the lock since it can be slow. ExportedCallStat previous = null; String previousMethodName = null; resultCallStats.sort(BinderCallsStats::compareByBinderClassAndCode); @@ -398,17 +456,6 @@ public class BinderCallsStats implements BinderInternal.Observer { exported.methodName = methodName; previous = exported; } - - // Debug entries added to help validate the data. - if (mAddDebugEntries && mBatteryStopwatch != null) { - resultCallStats.add(createDebugEntry("start_time_millis", mStartElapsedTime)); - resultCallStats.add(createDebugEntry("end_time_millis", SystemClock.elapsedRealtime())); - resultCallStats.add( - createDebugEntry("battery_time_millis", mBatteryStopwatch.getMillis())); - resultCallStats.add(createDebugEntry("sampling_interval", mPeriodicSamplingInterval)); - } - - return resultCallStats; } private ExportedCallStat createDebugEntry(String variableName, long value) { @@ -432,33 +479,24 @@ public class BinderCallsStats implements BinderInternal.Observer { } /** Writes the collected statistics to the supplied {@link PrintWriter}.*/ - public void dump(PrintWriter pw, AppIdToPackageMap packageMap, boolean verbose) { + public void dump(PrintWriter pw, AppIdToPackageMap packageMap, int workSourceUid, + boolean verbose) { synchronized (mLock) { - dumpLocked(pw, packageMap, verbose); + dumpLocked(pw, packageMap, workSourceUid, verbose); } } - private void dumpLocked(PrintWriter pw, AppIdToPackageMap packageMap, boolean verbose) { - long totalCallsCount = 0; - long totalRecordedCallsCount = 0; - long totalCpuTime = 0; + private void dumpLocked(PrintWriter pw, AppIdToPackageMap packageMap, int workSourceUid, + boolean verbose) { + if (workSourceUid != Process.INVALID_UID) { + verbose = true; + } pw.print("Start time: "); pw.println(DateFormat.format("yyyy-MM-dd HH:mm:ss", mStartCurrentTime)); pw.print("On battery time (ms): "); pw.println(mBatteryStopwatch != null ? mBatteryStopwatch.getMillis() : 0); pw.println("Sampling interval period: " + mPeriodicSamplingInterval); - final List<UidEntry> entries = new ArrayList<>(); - final int uidEntriesSize = mUidEntries.size(); - for (int i = 0; i < uidEntriesSize; i++) { - UidEntry e = mUidEntries.valueAt(i); - entries.add(e); - totalCpuTime += e.cpuTimeMicros; - totalRecordedCallsCount += e.recordedCallCount; - totalCallsCount += e.callCount; - } - - entries.sort(Comparator.<UidEntry>comparingDouble(value -> value.cpuTimeMicros).reversed()); final String datasetSizeDesc = verbose ? "" : "(top 90% by cpu time) "; final StringBuilder sb = new StringBuilder(); pw.println("Per-UID raw data " + datasetSizeDesc @@ -467,10 +505,15 @@ public class BinderCallsStats implements BinderInternal.Observer { + "latency_time_micros, max_latency_time_micros, exception_count, " + "max_request_size_bytes, max_reply_size_bytes, recorded_call_count, " + "call_count):"); - final List<ExportedCallStat> exportedCallStats = getExportedCallStats(); + final List<ExportedCallStat> exportedCallStats; + if (workSourceUid != Process.INVALID_UID) { + exportedCallStats = getExportedCallStats(workSourceUid); + } else { + exportedCallStats = getExportedCallStats(); + } exportedCallStats.sort(BinderCallsStats::compareByCpuDesc); for (ExportedCallStat e : exportedCallStats) { - if (e.methodName.startsWith(DEBUG_ENTRY_PREFIX)) { + if (e.methodName != null && e.methodName.startsWith(DEBUG_ENTRY_PREFIX)) { // Do not dump debug entries. continue; } @@ -494,6 +537,30 @@ public class BinderCallsStats implements BinderInternal.Observer { pw.println(sb); } pw.println(); + final List<UidEntry> entries = new ArrayList<>(); + long totalCallsCount = 0; + long totalRecordedCallsCount = 0; + long totalCpuTime = 0; + + if (workSourceUid != Process.INVALID_UID) { + UidEntry e = getUidEntry(workSourceUid); + entries.add(e); + totalCpuTime += e.cpuTimeMicros; + totalRecordedCallsCount += e.recordedCallCount; + totalCallsCount += e.callCount; + } else { + final int uidEntriesSize = mUidEntries.size(); + for (int i = 0; i < uidEntriesSize; i++) { + UidEntry e = mUidEntries.valueAt(i); + entries.add(e); + totalCpuTime += e.cpuTimeMicros; + totalRecordedCallsCount += e.recordedCallCount; + totalCallsCount += e.callCount; + } + entries.sort( + Comparator.<UidEntry>comparingDouble(value -> value.cpuTimeMicros).reversed()); + } + pw.println("Per-UID Summary " + datasetSizeDesc + "(cpu_time, % of total cpu_time, recorded_call_count, call_count, package/uid):"); final List<UidEntry> summaryEntries = verbose ? entries @@ -505,10 +572,13 @@ public class BinderCallsStats implements BinderInternal.Observer { entry.recordedCallCount, entry.callCount, uidStr)); } pw.println(); - pw.println(String.format(" Summary: total_cpu_time=%d, " - + "calls_count=%d, avg_call_cpu_time=%.0f", - totalCpuTime, totalCallsCount, (double) totalCpuTime / totalRecordedCallsCount)); - pw.println(); + if (workSourceUid == Process.INVALID_UID) { + pw.println(String.format(" Summary: total_cpu_time=%d, " + + "calls_count=%d, avg_call_cpu_time=%.0f", + totalCpuTime, totalCallsCount, + (double) totalCpuTime / totalRecordedCallsCount)); + pw.println(); + } pw.println("Exceptions thrown (exception_count, class_name):"); final List<Pair<String, Integer>> exceptionEntries = new ArrayList<>(); @@ -590,6 +660,22 @@ public class BinderCallsStats implements BinderInternal.Observer { } } + /** + * Marks the specified work source UID for total binder call tracking: detailed information + * will be recorded for all calls from this source ID. + * + * This is expensive and can cause memory pressure, therefore this mode should only be used + * for debugging. + */ + public void recordAllCallsForWorkSourceUid(int workSourceUid) { + setDetailedTracking(true); + + Slog.i(TAG, "Recording all Binder calls for UID: " + workSourceUid); + UidEntry uidEntry = getUidEntry(workSourceUid); + uidEntry.recordAllTransactions = true; + mRecordingAllTransactionsForUid = true; + } + public void setAddDebugEntries(boolean addDebugEntries) { mAddDebugEntries = addDebugEntries; } @@ -637,6 +723,7 @@ public class BinderCallsStats implements BinderInternal.Observer { if (mBatteryStopwatch != null) { mBatteryStopwatch.reset(); } + mRecordingAllTransactionsForUid = false; } } @@ -767,6 +854,8 @@ public class BinderCallsStats implements BinderInternal.Observer { public long cpuTimeMicros; // Call count that gets reset after delivery to BatteryStats public long incrementalCallCount; + // Indicates that all transactions for the UID must be tracked + public boolean recordAllTransactions; UidEntry(int uid) { this.workSourceUid = uid; diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java index f14d5f2bbbeb..2645b8e84cf1 100644 --- a/core/java/com/android/internal/os/BinderInternal.java +++ b/core/java/com/android/internal/os/BinderInternal.java @@ -85,9 +85,10 @@ public class BinderInternal { long timeStarted; // Should be set to one when an exception is thrown. boolean exceptionThrown; + // Detailed information should be recorded for this call when it ends. + public boolean recordedCall; } - /** * Responsible for resolving a work source. */ diff --git a/services/core/java/com/android/server/wm/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java index 51725cecbc74..73d148c1f233 100644 --- a/services/core/java/com/android/server/wm/ProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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,11 +14,9 @@ * limitations under the License. */ -package com.android.server.wm; +package com.android.internal.protolog; -import com.android.internal.annotations.VisibleForTesting; -import com.android.server.protolog.common.IProtoLogGroup; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.IProtoLogGroup; /** * Defines logging groups for ProtoLog. @@ -118,16 +116,6 @@ public enum ProtoLogGroup implements IProtoLogGroup { this.mLogToLogcat = logToLogcat; } - /** - * Test function for automated integration tests. Can be also called manually from adb shell. - */ - @VisibleForTesting - public static void testProtoLog() { - ProtoLog.e(ProtoLogGroup.TEST_GROUP, - "Test completed successfully: %b %d %o %x %e %g %f %% %s.", - true, 1, 2, 3, 0.4, 0.5, 0.6, "ok"); - } - private static class Consts { private static final String TAG_WM = "WindowManager"; diff --git a/services/core/java/com/android/server/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java index c9d42c854b54..6874f10e6abc 100644 --- a/services/core/java/com/android/server/protolog/ProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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,20 +14,20 @@ * limitations under the License. */ -package com.android.server.protolog; - -import static com.android.server.protolog.ProtoLogFileProto.LOG; -import static com.android.server.protolog.ProtoLogFileProto.MAGIC_NUMBER; -import static com.android.server.protolog.ProtoLogFileProto.MAGIC_NUMBER_H; -import static com.android.server.protolog.ProtoLogFileProto.MAGIC_NUMBER_L; -import static com.android.server.protolog.ProtoLogFileProto.REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS; -import static com.android.server.protolog.ProtoLogFileProto.VERSION; -import static com.android.server.protolog.ProtoLogMessage.BOOLEAN_PARAMS; -import static com.android.server.protolog.ProtoLogMessage.DOUBLE_PARAMS; -import static com.android.server.protolog.ProtoLogMessage.ELAPSED_REALTIME_NANOS; -import static com.android.server.protolog.ProtoLogMessage.MESSAGE_HASH; -import static com.android.server.protolog.ProtoLogMessage.SINT64_PARAMS; -import static com.android.server.protolog.ProtoLogMessage.STR_PARAMS; +package com.android.internal.protolog; + +import static com.android.internal.protolog.ProtoLogFileProto.LOG; +import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER; +import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_H; +import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_L; +import static com.android.internal.protolog.ProtoLogFileProto.REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS; +import static com.android.internal.protolog.ProtoLogFileProto.VERSION; +import static com.android.internal.protolog.ProtoLogMessage.BOOLEAN_PARAMS; +import static com.android.internal.protolog.ProtoLogMessage.DOUBLE_PARAMS; +import static com.android.internal.protolog.ProtoLogMessage.ELAPSED_REALTIME_NANOS; +import static com.android.internal.protolog.ProtoLogMessage.MESSAGE_HASH; +import static com.android.internal.protolog.ProtoLogMessage.SINT64_PARAMS; +import static com.android.internal.protolog.ProtoLogMessage.STR_PARAMS; import android.annotation.Nullable; import android.os.ShellCommand; @@ -36,10 +36,9 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.protolog.common.IProtoLogGroup; -import com.android.server.protolog.common.LogDataType; +import com.android.internal.protolog.common.IProtoLogGroup; +import com.android.internal.protolog.common.LogDataType; import com.android.internal.util.TraceBuffer; -import com.android.server.wm.ProtoLogGroup; import java.io.File; import java.io.IOException; @@ -62,7 +61,7 @@ public class ProtoLogImpl { * Must be invoked after every action that could change the result of {@link #isEnabled}, eg. * starting / stopping proto log, or enabling / disabling log groups. */ - static Runnable sCacheUpdater = () -> { }; + public static Runnable sCacheUpdater = () -> { }; private static void addLogGroupEnum(IProtoLogGroup[] config) { for (IProtoLogGroup group : config) { @@ -289,9 +288,7 @@ public class ProtoLogImpl { } } - - @VisibleForTesting - ProtoLogImpl(File file, int bufferCapacity, ProtoLogViewerConfigReader viewerConfig) { + public ProtoLogImpl(File file, int bufferCapacity, ProtoLogViewerConfigReader viewerConfig) { mLogFile = file; mBuffer = new TraceBuffer(bufferCapacity); mViewerConfig = viewerConfig; diff --git a/services/core/java/com/android/server/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java index 494421717800..e381d30da524 100644 --- a/services/core/java/com/android/server/protolog/ProtoLogViewerConfigReader.java +++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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,9 +14,7 @@ * limitations under the License. */ -package com.android.server.protolog; - -import static com.android.server.protolog.ProtoLogImpl.logAndPrintln; +package com.android.internal.protolog; import org.json.JSONException; import org.json.JSONObject; @@ -80,16 +78,17 @@ public class ProtoLogViewerConfigReader { // Not a messageHash - skip it } } - logAndPrintln(pw, "Loaded " + mLogMessageMap.size() + " log definitions from " - + viewerConfigFilename); + ProtoLogImpl.logAndPrintln(pw, "Loaded " + mLogMessageMap.size() + + " log definitions from " + viewerConfigFilename); } catch (FileNotFoundException e) { - logAndPrintln(pw, "Unable to load log definitions: File " + ProtoLogImpl.logAndPrintln(pw, "Unable to load log definitions: File " + viewerConfigFilename + " not found." + e); } catch (IOException e) { - logAndPrintln(pw, "Unable to load log definitions: IOException while reading " + ProtoLogImpl.logAndPrintln(pw, + "Unable to load log definitions: IOException while reading " + viewerConfigFilename + ". " + e); } catch (JSONException e) { - logAndPrintln(pw, + ProtoLogImpl.logAndPrintln(pw, "Unable to load log definitions: JSON parsing exception while reading " + viewerConfigFilename + ". " + e); } diff --git a/services/core/java/com/android/server/protolog/common/BitmaskConversionException.java b/core/java/com/android/internal/protolog/common/BitmaskConversionException.java index 7bb27b2d9bcd..68b9d6910b57 100644 --- a/services/core/java/com/android/server/protolog/common/BitmaskConversionException.java +++ b/core/java/com/android/internal/protolog/common/BitmaskConversionException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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.protolog.common; +package com.android.internal.protolog.common; /** * Error while converting a bitmask representing a list of LogDataTypes. diff --git a/services/core/java/com/android/server/protolog/common/IProtoLogGroup.java b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java index 2c65341453e9..e3db46832a6f 100644 --- a/services/core/java/com/android/server/protolog/common/IProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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.protolog.common; +package com.android.internal.protolog.common; /** * Defines a log group configuration object for ProtoLog. Should be implemented as en enum. diff --git a/services/core/java/com/android/server/protolog/common/InvalidFormatStringException.java b/core/java/com/android/internal/protolog/common/InvalidFormatStringException.java index 947bf98eea3c..97d3dfb7e6c2 100644 --- a/services/core/java/com/android/server/protolog/common/InvalidFormatStringException.java +++ b/core/java/com/android/internal/protolog/common/InvalidFormatStringException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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.protolog.common; +package com.android.internal.protolog.common; /** * Unsupported/invalid message format string error. diff --git a/services/core/java/com/android/server/protolog/common/LogDataType.java b/core/java/com/android/internal/protolog/common/LogDataType.java index e73b41abddc7..651932a7ba7e 100644 --- a/services/core/java/com/android/server/protolog/common/LogDataType.java +++ b/core/java/com/android/internal/protolog/common/LogDataType.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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.protolog.common; +package com.android.internal.protolog.common; import java.util.ArrayList; import java.util.List; diff --git a/services/core/java/com/android/server/protolog/common/ProtoLog.java b/core/java/com/android/internal/protolog/common/ProtoLog.java index b631bcb23f5f..ab58d351d3b9 100644 --- a/services/core/java/com/android/server/protolog/common/ProtoLog.java +++ b/core/java/com/android/internal/protolog/common/ProtoLog.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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.protolog.common; +package com.android.internal.protolog.common; /** * ProtoLog API - exposes static logging methods. Usage of this API is similar diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java index 9bf05135c4c5..a23fc4b57b45 100644 --- a/core/java/com/android/internal/util/ScreenshotHelper.java +++ b/core/java/com/android/internal/util/ScreenshotHelper.java @@ -291,7 +291,7 @@ public class ScreenshotHelper { }; Message msg = Message.obtain(null, screenshotType, screenshotRequest); - final ServiceConnection myConn = mScreenshotConnection; + Handler h = new Handler(handler.getLooper()) { @Override public void handleMessage(Message msg) { @@ -304,8 +304,8 @@ public class ScreenshotHelper { break; case SCREENSHOT_MSG_PROCESS_COMPLETE: synchronized (mScreenshotLock) { - if (myConn != null && mScreenshotConnection == myConn) { - mContext.unbindService(myConn); + if (mScreenshotConnection != null) { + mContext.unbindService(mScreenshotConnection); mScreenshotConnection = null; mScreenshotService = null; } @@ -368,6 +368,7 @@ public class ScreenshotHelper { } } else { Messenger messenger = new Messenger(mScreenshotService); + try { messenger.send(msg); } catch (RemoteException e) { diff --git a/core/java/com/android/internal/util/StatLogger.java b/core/java/com/android/internal/util/StatLogger.java index 29568d5020e3..2d65090ce51e 100644 --- a/core/java/com/android/internal/util/StatLogger.java +++ b/core/java/com/android/internal/util/StatLogger.java @@ -84,7 +84,7 @@ public class StatLogger { * give it back to the {@link #logDurationStat(int, long)}} after the event. */ public long getTime() { - return SystemClock.elapsedRealtimeNanos() / 1000; + return SystemClock.uptimeNanos() / 1000; } /** diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp index b1f600053b9b..2fba445428f4 100644 --- a/core/jni/android_os_SystemClock.cpp +++ b/core/jni/android_os_SystemClock.cpp @@ -37,10 +37,12 @@ namespace android { static_assert(std::is_same<int64_t, jlong>::value, "jlong isn't an int64_t"); static_assert(std::is_same<decltype(uptimeMillis()), int64_t>::value, "uptimeMillis signature change, expected int64_t return value"); +static_assert(std::is_same<decltype(uptimeNanos()), int64_t>::value, + "uptimeNanos signature change, expected int64_t return value"); static_assert(std::is_same<decltype(elapsedRealtime()), int64_t>::value, - "uptimeMillis signature change, expected int64_t return value"); + "elapsedRealtime signature change, expected int64_t return value"); static_assert(std::is_same<decltype(elapsedRealtimeNano()), int64_t>::value, - "uptimeMillis signature change, expected int64_t return value"); + "elapsedRealtimeNano signature change, expected int64_t return value"); /* * native public static long currentThreadTimeMillis(); @@ -76,6 +78,7 @@ static const JNINativeMethod gMethods[] = { // All of these are @CriticalNative, so we can defer directly to SystemClock.h for // some of these { "uptimeMillis", "()J", (void*) uptimeMillis }, + { "uptimeNanos", "()J", (void*) uptimeNanos }, { "elapsedRealtime", "()J", (void*) elapsedRealtime }, { "elapsedRealtimeNanos", "()J", (void*) elapsedRealtimeNano }, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index d6a773fb91e0..85b4fe197980 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -116,7 +116,6 @@ static struct { jfieldID width; jfieldID height; jfieldID useIdentityTransform; - jfieldID rotation; } gDisplayCaptureArgsClassInfo; static struct { @@ -325,8 +324,6 @@ static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env, captureArgs.useIdentityTransform = env->GetBooleanField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.useIdentityTransform); - captureArgs.rotation = ui::toRotation( - env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.rotation)); return captureArgs; } @@ -1849,8 +1846,6 @@ int register_android_view_SurfaceControl(JNIEnv* env) GetFieldIDOrDie(env, displayCaptureArgsClazz, "mHeight", "I"); gDisplayCaptureArgsClassInfo.useIdentityTransform = GetFieldIDOrDie(env, displayCaptureArgsClazz, "mUseIdentityTransform", "Z"); - gDisplayCaptureArgsClassInfo.rotation = - GetFieldIDOrDie(env, displayCaptureArgsClazz, "mRotation", "I"); jclass layerCaptureArgsClazz = FindClassOrDie(env, "android/view/SurfaceControl$LayerCaptureArgs"); diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 1014fbb73877..0d65bd1cf9bb 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -744,6 +744,41 @@ enum Action { // CATEGORY: SETTINGS // OS: R ACTION_CONFIRM_SIM_DELETION_OFF = 1739; + + // ACTION: Settings > System > Gestures > Double tap > Toggle on Double tap + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ENABLED = 1740; + + // ACTION: Settings > System > Gestures > Double tap > Toggle off Double tap + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_DISABLED = 1741; + + // ACTION: Settings > System > Gestures > Double tap > Invoke Assistant + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ACTION_ASSISTANT = 1742; + + // ACTION: Settings > System > Gestures > Double tap > Take screenshot + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ACTION_SCREENSHOT = 1743; + + // ACTION: Settings > System > Gestures > Double tap > Play and pause + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ACTION_PLAY_PAUSE = 1744; + + // ACTION: Settings > System > Gestures > Double tap > Open app overview + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ACTION_OVERVIEW = 1745; + + // ACTION: Settings > System > Gestures > Double tap > Open notification shade + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ACTION_NOTIFICATION_SHADE = 1746; } /** diff --git a/core/proto/android/app/tvsettings_enums.proto b/core/proto/android/app/tvsettings_enums.proto index 31c5dd6b730a..4a3c59477f2f 100644 --- a/core/proto/android/app/tvsettings_enums.proto +++ b/core/proto/android/app/tvsettings_enums.proto @@ -168,7 +168,11 @@ enum ItemId { // Google Assistant > Personal results (toggle) ACCOUNT_SLICE_REG_ACCOUNT_ASSISTANT_PERSONAL_RESULTS = 0x12134000; - // Reserving [0x12140000, 0x12190000] for possible future settings + // TvSettings > Account & Sign In (Slice) > [A regular account] > + // Apps only mode (toggle) + ACCOUNT_SLICE_REG_ACCOUNT_APPS_ONLY_MODE = 0x12140000; + + // Reserving [0x12150000, 0x12190000] for possible future settings // TvSettings > Account & Sign In (Slice) > [A regular account] > Remove ACCOUNT_SLICE_REG_ACCOUNT_REMOVE = 0x121A0000; diff --git a/core/proto/android/server/protolog.proto b/core/proto/android/internal/protolog.proto index 34dc55b959c2..fee7a878f860 100644 --- a/core/proto/android/server/protolog.proto +++ b/core/proto/android/internal/protolog.proto @@ -16,7 +16,7 @@ syntax = "proto2"; -package com.android.server.protolog; +package com.android.internal.protolog; option java_multiple_files = true; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index fe290f3e97e8..edb972730f69 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1342,7 +1342,7 @@ android:priority="800" /> <!-- Allows an application to access data from sensors that the user uses to - measure what is happening inside his/her body, such as heart rate. + measure what is happening inside their body, such as heart rate. <p>Protection level: dangerous --> <permission android:name="android.permission.BODY_SENSORS" android:permissionGroup="android.permission-group.UNDEFINED" diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 2e4169e15c3b..4f55bf51c826 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -470,10 +470,10 @@ <string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permet que l\'aplicació impedeixi que la tauleta entri en repòs."</string> <string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permet que l\'aplicació impedeixi que el dispositiu Android TV entri en repòs."</string> <string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permet que l\'aplicació impedeixi que el telèfon entri en repòs."</string> - <string name="permlab_transmitIr" msgid="8077196086358004010">"transmissió d\'infraroigs"</string> - <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"Permet que l\'aplicació utilitzi el transmissor d\'infraroigs de la tauleta."</string> - <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"Permet que l\'aplicació faci servir el transmissor d\'infraroigs del dispositiu Android TV."</string> - <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"Permet que l\'aplicació utilitzi el transmissor d\'infraroigs del telèfon."</string> + <string name="permlab_transmitIr" msgid="8077196086358004010">"transmissió d\'infrarojos"</string> + <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"Permet que l\'aplicació utilitzi el transmissor d\'infrarojos de la tauleta."</string> + <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"Permet que l\'aplicació faci servir el transmissor d\'infrarojos del dispositiu Android TV."</string> + <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"Permet que l\'aplicació utilitzi el transmissor d\'infrarojos del telèfon."</string> <string name="permlab_setWallpaper" msgid="6959514622698794511">"establir fons de pantalla"</string> <string name="permdesc_setWallpaper" msgid="2973996714129021397">"Permet que l\'aplicació estableixi el fons de pantalla del sistema."</string> <string name="permlab_setWallpaperHints" msgid="1153485176642032714">"ajustament de la mida del fons de pantalla"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index fd7b1b2ab55a..bb79c2193a36 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -1633,7 +1633,7 @@ <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"निष्क्रिय"</string> <string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> लाई तपाईंको यन्त्र पूर्ण रूपमा नियन्त्रण गर्न दिने हो?"</string> <string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"तपाईंले <xliff:g id="SERVICE">%1$s</xliff:g> सक्रिय गर्नुभयो भने तपाईंको यन्त्रले डेटा इन्क्रिप्ट गर्ने सुविधाको स्तरोन्नति गर्न तपाईंको स्क्रिन लक सुविधाको प्रयोग गर्ने छैन।"</string> - <string name="accessibility_service_warning_description" msgid="291674995220940133">"तपाईंलाई पहुँच राख्न आवश्यक पर्ने कुरामा सहयोग गर्ने अनुप्रयोगहरूमाथि पूर्ण नियन्त्रण गर्नु उपयुक्त हुन्छ तर अधिकांश अनुप्रयोगहरूका हकमा यस्तो नियन्त्रण उपयुक्त हुँदैन।"</string> + <string name="accessibility_service_warning_description" msgid="291674995220940133">"तपाईंलाई पहुँच राख्न आवश्यक पर्ने कुरामा सहयोग गर्ने एपमाथि पूर्ण नियन्त्रण गर्नु उपयुक्त हुन्छ तर अधिकांश अनुप्रयोगहरूका हकमा यस्तो नियन्त्रण उपयुक्त हुँदैन।"</string> <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"स्क्रिन हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string> <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"यसले स्क्रिनमा देखिने सबै सामग्री पढ्न सक्छ र अन्य एपहरूमा उक्त सामग्री देखाउन सक्छ।"</string> <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"कारबाहीहरू हेर्नुहोस् र तिनमा कार्य गर्नुहोस्"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 8913e8b18750..f99be880cbe3 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1823,6 +1823,8 @@ <string name="config_defaultCallScreening" translatable="false"></string> <!-- The name of the package that will hold the system gallery role. --> <string name="config_systemGallery" translatable="false">com.android.gallery3d</string> + <!-- The name of the package that will hold the system cluster service role. --> + <string name="config_systemAutomotiveCluster" translatable="false"></string> <!-- The name of the package that will be allowed to change its components' label/icon. --> <string name="config_overrideComponentUiPackage" translatable="false"></string> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 303fde6705c2..1e2d554a088b 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3069,7 +3069,8 @@ </public-group> <public-group type="string" first-id="0x01040028"> - <!-- string definitions go here --> + <!-- @hide @SystemApi @TestApi --> + <public name="config_systemAutomotiveCluster" /> </public-group> <public-group type="id" first-id="0x01020055"> diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml index d8ec72f33ddc..166edca3d046 100644 --- a/core/res/res/xml/power_profile.xml +++ b/core/res/res/xml/power_profile.xml @@ -20,7 +20,7 @@ <device name="Android"> <!-- Most values are the incremental current used by a feature, in mA (measured at nominal voltage). - The default values are deliberately incorrect dummy values. + The default values are deliberately incorrect values. OEM's must measure and provide actual values before shipping a device. Example real-world values are given in comments, but they diff --git a/core/tests/coretests/src/android/app/WindowContextTest.java b/core/tests/coretests/src/android/app/WindowContextTest.java index 630e16ac80d4..0f9bc4bee99a 100644 --- a/core/tests/coretests/src/android/app/WindowContextTest.java +++ b/core/tests/coretests/src/android/app/WindowContextTest.java @@ -30,7 +30,6 @@ import android.view.Display; import android.view.IWindowManager; import android.view.WindowManagerGlobal; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -47,7 +46,6 @@ import org.junit.runner.RunWith; * <p>This test class is a part of Window Manager Service tests and specified in * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ -@FlakyTest(bugId = 150812449, detail = "Remove after confirmed it's stable.") @RunWith(AndroidJUnit4.class) @SmallTest @Presubmit diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index e0d702e98595..2bf9848304ad 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -24,6 +24,7 @@ import static android.app.servertransaction.TestUtils.resultInfoList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.app.ContentProviderHolder; import android.app.IApplicationThread; import android.app.IInstrumentationWatcher; import android.app.IUiAutomationConnection; @@ -665,5 +666,10 @@ public class TransactionParcelTests { public void performDirectAction(IBinder activityToken, String actionId, Bundle arguments, RemoteCallback cancellationCallback, RemoteCallback resultCallback) { } + + @Override + public void notifyContentProviderPublishStatus(ContentProviderHolder holder, String auth, + int userId, boolean published) { + } } } diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java index 8a36f1dc057b..72391f4d7dec 100644 --- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java +++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java @@ -33,9 +33,11 @@ public class TimeZoneCapabilitiesTest { public void testEquals() { TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID) .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED) + .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED) .setSuggestManualTimeZone(CAPABILITY_POSSESSED); TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID) .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED) + .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED) .setSuggestManualTimeZone(CAPABILITY_POSSESSED); { TimeZoneCapabilities one = builder1.build(); @@ -57,6 +59,20 @@ public class TimeZoneCapabilitiesTest { assertEquals(one, two); } + builder2.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED); + { + TimeZoneCapabilities one = builder1.build(); + TimeZoneCapabilities two = builder2.build(); + assertNotEquals(one, two); + } + + builder1.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED); + { + TimeZoneCapabilities one = builder1.build(); + TimeZoneCapabilities two = builder2.build(); + assertEquals(one, two); + } + builder2.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED); { TimeZoneCapabilities one = builder1.build(); @@ -76,12 +92,16 @@ public class TimeZoneCapabilitiesTest { public void testParcelable() { TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID) .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED) + .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED) .setSuggestManualTimeZone(CAPABILITY_POSSESSED); assertRoundTripParcelable(builder.build()); builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED); assertRoundTripParcelable(builder.build()); + builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED); + assertRoundTripParcelable(builder.build()); + builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED); assertRoundTripParcelable(builder.build()); } diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java index ac7e9c437b63..00dc73ed269f 100644 --- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java +++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java @@ -29,8 +29,9 @@ public class TimeZoneConfigurationTest { @Test public void testBuilder_copyConstructor() { - TimeZoneConfiguration.Builder builder1 = - new TimeZoneConfiguration.Builder().setAutoDetectionEnabled(true); + TimeZoneConfiguration.Builder builder1 = new TimeZoneConfiguration.Builder() + .setAutoDetectionEnabled(true) + .setGeoDetectionEnabled(true); TimeZoneConfiguration configuration1 = builder1.build(); TimeZoneConfiguration configuration2 = @@ -41,16 +42,15 @@ public class TimeZoneConfigurationTest { @Test public void testIsComplete() { - TimeZoneConfiguration incompleteConfiguration = - new TimeZoneConfiguration.Builder() - .build(); - assertFalse(incompleteConfiguration.isComplete()); + TimeZoneConfiguration.Builder builder = + new TimeZoneConfiguration.Builder(); + assertFalse(builder.build().isComplete()); - TimeZoneConfiguration completeConfiguration = - new TimeZoneConfiguration.Builder() - .setAutoDetectionEnabled(true) - .build(); - assertTrue(completeConfiguration.isComplete()); + builder.setAutoDetectionEnabled(true); + assertFalse(builder.build().isComplete()); + + builder.setGeoDetectionEnabled(true); + assertTrue(builder.build().isComplete()); } @Test @@ -122,6 +122,27 @@ public class TimeZoneConfigurationTest { TimeZoneConfiguration two = builder2.build(); assertEquals(one, two); } + + builder1.setGeoDetectionEnabled(true); + { + TimeZoneConfiguration one = builder1.build(); + TimeZoneConfiguration two = builder2.build(); + assertNotEquals(one, two); + } + + builder2.setGeoDetectionEnabled(false); + { + TimeZoneConfiguration one = builder1.build(); + TimeZoneConfiguration two = builder2.build(); + assertNotEquals(one, two); + } + + builder1.setGeoDetectionEnabled(false); + { + TimeZoneConfiguration one = builder1.build(); + TimeZoneConfiguration two = builder2.build(); + assertEquals(one, two); + } } @Test @@ -135,5 +156,11 @@ public class TimeZoneConfigurationTest { builder.setAutoDetectionEnabled(false); assertRoundTripParcelable(builder.build()); + + builder.setGeoDetectionEnabled(false); + assertRoundTripParcelable(builder.build()); + + builder.setGeoDetectionEnabled(true); + assertRoundTripParcelable(builder.build()); } } diff --git a/core/tests/coretests/src/android/view/WindowMetricsTest.java b/core/tests/coretests/src/android/view/WindowMetricsTest.java index ddc977d380ae..96df9dda23c7 100644 --- a/core/tests/coretests/src/android/view/WindowMetricsTest.java +++ b/core/tests/coretests/src/android/view/WindowMetricsTest.java @@ -27,7 +27,6 @@ import android.hardware.display.DisplayManager; import android.os.Handler; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -46,7 +45,6 @@ import org.junit.runner.RunWith; * <p>This test class is a part of Window Manager Service tests and specified in * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ -@FlakyTest(bugId = 148789183, detail = "Remove after confirmed it's stable.") @RunWith(AndroidJUnit4.class) @SmallTest @Presubmit diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java index 188ba9e0ca0e..96250db4aa51 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.os.Binder; import android.os.Handler; @@ -44,6 +45,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Random; @@ -493,7 +495,9 @@ public class BinderCallsStatsTest { bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); PrintWriter pw = new PrintWriter(new StringWriter()); - bcs.dump(pw, new AppIdToPackageMap(new HashMap<>()), true); + bcs.dump(pw, new AppIdToPackageMap(new HashMap<>()), Process.INVALID_UID, true); + + bcs.dump(pw, new AppIdToPackageMap(new HashMap<>()), WORKSOURCE_UID, true); } @Test @@ -606,8 +610,8 @@ public class BinderCallsStatsTest { assertEquals("-1", callStats.methodName); assertEquals("com.android.internal.os.BinderCallsStats$OverflowBinder", callStats.className); - assertEquals(false , callStats.screenInteractive); - assertEquals(-1 , callStats.callingUid); + assertEquals(false, callStats.screenInteractive); + assertEquals(-1, callStats.callingUid); } @Test @@ -785,7 +789,7 @@ public class BinderCallsStatsTest { bcs.time += 30; bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); - for (Runnable runnable: mHandler.mRunnables) { + for (Runnable runnable : mHandler.mRunnables) { // Execute all pending runnables. Ignore the delay. runnable.run(); } @@ -839,6 +843,53 @@ public class BinderCallsStatsTest { assertEquals(3, tids[2]); } + @Test + public void testTrackingSpecificWorksourceUid() { + mDeviceState.setCharging(true); + + Binder binder = new Binder(); + + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.recordAllCallsForWorkSourceUid(WORKSOURCE_UID); + + int[] transactions = {41, 42, 43, 42, 43, 43}; + int[] durationsMs = {100, 200, 300, 400, 500, 600}; + + for (int i = 0; i < transactions.length; i++) { + CallSession callSession = bcs.callStarted(binder, transactions[i], WORKSOURCE_UID); + bcs.time += durationsMs[i]; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); + } + + BinderCallsStats.UidEntry uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); + Assert.assertNotNull(uidEntry); + assertEquals(6, uidEntry.callCount); + + Collection<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList(); + assertEquals(3, callStatsList.size()); + for (BinderCallsStats.CallStat callStat : callStatsList) { + switch (callStat.transactionCode) { + case 41: + assertEquals(1, callStat.callCount); + assertEquals(1, callStat.incrementalCallCount); + assertEquals(100, callStat.cpuTimeMicros); + break; + case 42: + assertEquals(2, callStat.callCount); + assertEquals(2, callStat.incrementalCallCount); + assertEquals(200 + 400, callStat.cpuTimeMicros); + break; + case 43: + assertEquals(3, callStat.callCount); + assertEquals(3, callStat.incrementalCallCount); + assertEquals(300 + 500 + 600, callStat.cpuTimeMicros); + break; + default: + fail("Unexpected transaction code: " + callStat.transactionCode); + } + } + } + private static class TestHandler extends Handler { ArrayList<Runnable> mRunnables = new ArrayList<>(); diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 2a8aa8c3e5b7..a11678189bad 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -238,12 +238,8 @@ EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavi return config; } -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); - void EglManager::initExtensions() { auto extensions = StringUtils::split(eglQueryString(mEglDisplay, EGL_EXTENSIONS)); - auto extensionsAndroid = - StringUtils::split(eglQueryStringImplementationANDROID(mEglDisplay, EGL_EXTENSIONS)); // For our purposes we don't care if EGL_BUFFER_AGE is a result of // EGL_EXT_buffer_age or EGL_KHR_partial_update as our usage is covered @@ -265,10 +261,7 @@ void EglManager::initExtensions() { EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context"); EglExtensions.fenceSync = extensions.has("EGL_KHR_fence_sync"); EglExtensions.waitSync = extensions.has("EGL_KHR_wait_sync"); - - // EGL_ANDROID_native_fence_sync is not exposed to applications, so access - // this through the private Android-specific query instead. - EglExtensions.nativeFenceSync = extensionsAndroid.has("EGL_ANDROID_native_fence_sync"); + EglExtensions.nativeFenceSync = extensions.has("EGL_ANDROID_native_fence_sync"); } bool EglManager::hasEglContext() { diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 6e3fb1991acc..d4fb1be56890 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -147,6 +147,19 @@ public final class AudioDeviceInfo { // {@link android.media.audiopolicy.AudioMix#ROUTE_FLAG_LOOP_BACK} flag. public static final int TYPE_REMOTE_SUBMIX = 25; + /** + * A device type describing a Bluetooth Low Energy (BLE) audio headset or headphones. + * Headphones are grouped with headsets when the device is a sink: + * the features of headsets and headphones with regard to playback are the same. + */ + public static final int TYPE_BLE_HEADSET = 26; + + /** + * A device type describing a Bluetooth Low Energy (BLE) audio speaker. + */ + public static final int TYPE_BLE_SPEAKER = 27; + + /** @hide */ @IntDef(flag = false, prefix = "TYPE", value = { TYPE_BUILTIN_EARPIECE, @@ -171,7 +184,9 @@ public final class AudioDeviceInfo { TYPE_HEARING_AID, TYPE_BUILTIN_MIC, TYPE_FM_TUNER, - TYPE_TV_TUNER } + TYPE_TV_TUNER, + TYPE_BLE_HEADSET, + TYPE_BLE_SPEAKER} ) @Retention(RetentionPolicy.SOURCE) public @interface AudioDeviceType {} @@ -193,7 +208,8 @@ public final class AudioDeviceInfo { TYPE_LINE_ANALOG, TYPE_LINE_DIGITAL, TYPE_IP, - TYPE_BUS } + TYPE_BUS, + TYPE_BLE_HEADSET} ) @Retention(RetentionPolicy.SOURCE) public @interface AudioDeviceTypeIn {} @@ -219,7 +235,9 @@ public final class AudioDeviceInfo { TYPE_AUX_LINE, TYPE_IP, TYPE_BUS, - TYPE_HEARING_AID } + TYPE_HEARING_AID, + TYPE_BLE_HEADSET, + TYPE_BLE_SPEAKER} ) @Retention(RetentionPolicy.SOURCE) public @interface AudioDeviceTypeOut {} @@ -248,7 +266,8 @@ public final class AudioDeviceInfo { case TYPE_BUS: case TYPE_HEARING_AID: case TYPE_BUILTIN_SPEAKER_SAFE: - case TYPE_REMOTE_SUBMIX: + case TYPE_BLE_HEADSET: + case TYPE_BLE_SPEAKER: return true; default: return false; @@ -275,6 +294,7 @@ public final class AudioDeviceInfo { case TYPE_IP: case TYPE_BUS: case TYPE_REMOTE_SUBMIX: + case TYPE_BLE_HEADSET: return true; default: return false; @@ -527,6 +547,8 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPEAKER_SAFE, TYPE_BUILTIN_SPEAKER_SAFE); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLE_HEADSET, TYPE_BLE_HEADSET); + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLE_SPEAKER, TYPE_BLE_SPEAKER); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO); @@ -547,6 +569,7 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_IP, TYPE_IP); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUS, TYPE_BUS); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLE_HEADSET, TYPE_BLE_HEADSET); // privileges mapping to output device EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray(); @@ -576,6 +599,8 @@ public final class AudioDeviceInfo { EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_SPEAKER_SAFE, AudioSystem.DEVICE_OUT_SPEAKER_SAFE); EXT_TO_INT_DEVICE_MAPPING.put(TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_OUT_REMOTE_SUBMIX); + EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_OUT_BLE_HEADSET); + EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_SPEAKER, AudioSystem.DEVICE_OUT_BLE_SPEAKER); } } diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java index 42d0f0cc13c5..f6b04540c5c7 100644 --- a/media/java/android/media/AudioDevicePort.java +++ b/media/java/android/media/AudioDevicePort.java @@ -70,7 +70,9 @@ public class AudioDevicePort extends AudioPort { * {@link AudioManager#DEVICE_IN_USB_DEVICE}) use an address composed of the ALSA card number * and device number: "card=2;device=1" * - Bluetooth devices ({@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO}, - * {@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO}, {@link AudioManager#DEVICE_OUT_BLUETOOTH_A2DP}) + * {@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO}, + * {@link AudioManager#DEVICE_OUT_BLUETOOTH_A2DP}), + * {@link AudioManager#DEVICE_OUT_BLE_HEADSET}, {@link AudioManager#DEVICE_OUT_BLE_SPEAKER}) * use the MAC address of the bluetooth device in the form "00:11:22:AA:BB:CC" as reported by * {@link BluetoothDevice#getAddress()}. * - Deivces that do not have an address will indicate an empty string "". diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index e0da5d9deb7c..a16e063fe969 100755 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -4530,6 +4530,18 @@ public class AudioManager { */ public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM; /** @hide + * The audio output device code for echo reference injection point. + */ + public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER; + /** @hide + * The audio output device code for a BLE audio headset. + */ + public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET; + /** @hide + * The audio output device code for a BLE audio speaker. + */ + public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER; + /** @hide * This is not used as a returned value from {@link #getDevicesForStream}, but could be * used in the future in a set method to select whatever default device is chosen by the * platform-specific implementation. @@ -4613,6 +4625,14 @@ public class AudioManager { * The audio input device code for audio loopback */ public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK; + /** @hide + * The audio input device code for an echo reference capture point. + */ + public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE; + /** @hide + * The audio input device code for a BLE audio headset. + */ + public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET; /** * Return true if the device code corresponds to an output device. diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index dbf25426a382..243ec1f1fcd0 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -867,6 +867,12 @@ public class AudioSystem public static final int DEVICE_OUT_USB_HEADSET = 0x4000000; /** @hide */ public static final int DEVICE_OUT_HEARING_AID = 0x8000000; + /** @hide */ + public static final int DEVICE_OUT_ECHO_CANCELLER = 0x10000000; + /** @hide */ + public static final int DEVICE_OUT_BLE_HEADSET = 0x20000000; + /** @hide */ + public static final int DEVICE_OUT_BLE_SPEAKER = 0x20000001; /** @hide */ public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT; @@ -891,6 +897,8 @@ public class AudioSystem public static final Set<Integer> DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET; /** @hide */ public static final Set<Integer> DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET; + /** @hide */ + public static final Set<Integer> DEVICE_OUT_ALL_BLE_SET; static { DEVICE_OUT_ALL_SET = new HashSet<>(); DEVICE_OUT_ALL_SET.add(DEVICE_OUT_EARPIECE); @@ -921,6 +929,9 @@ public class AudioSystem DEVICE_OUT_ALL_SET.add(DEVICE_OUT_PROXY); DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_HEADSET); DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HEARING_AID); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_ECHO_CANCELLER); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLE_HEADSET); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLE_SPEAKER); DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DEFAULT); DEVICE_OUT_ALL_A2DP_SET = new HashSet<>(); @@ -946,6 +957,10 @@ public class AudioSystem DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET = new HashSet<>(); DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.addAll(DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET); DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.add(DEVICE_OUT_SPEAKER); + + DEVICE_OUT_ALL_BLE_SET = new HashSet<>(); + DEVICE_OUT_ALL_BLE_SET.add(DEVICE_OUT_BLE_HEADSET); + DEVICE_OUT_ALL_BLE_SET.add(DEVICE_OUT_BLE_SPEAKER); } // input devices @@ -1020,6 +1035,8 @@ public class AudioSystem /** @hide */ public static final int DEVICE_IN_ECHO_REFERENCE = DEVICE_BIT_IN | 0x10000000; /** @hide */ + public static final int DEVICE_IN_BLE_HEADSET = DEVICE_BIT_IN | 0x20000000; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT; @@ -1057,6 +1074,7 @@ public class AudioSystem DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_BLE); DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI_ARC); DEVICE_IN_ALL_SET.add(DEVICE_IN_ECHO_REFERENCE); + DEVICE_IN_ALL_SET.add(DEVICE_IN_BLE_HEADSET); DEVICE_IN_ALL_SET.add(DEVICE_IN_DEFAULT); DEVICE_IN_ALL_SCO_SET = new HashSet<>(); @@ -1119,6 +1137,9 @@ public class AudioSystem /** @hide */ public static final String DEVICE_OUT_PROXY_NAME = "proxy"; /** @hide */ public static final String DEVICE_OUT_USB_HEADSET_NAME = "usb_headset"; /** @hide */ public static final String DEVICE_OUT_HEARING_AID_NAME = "hearing_aid_out"; + /** @hide */ public static final String DEVICE_OUT_ECHO_CANCELLER_NAME = "echo_canceller"; + /** @hide */ public static final String DEVICE_OUT_BLE_HEADSET_NAME = "ble_headset"; + /** @hide */ public static final String DEVICE_OUT_BLE_SPEAKER_NAME = "ble_speaker"; /** @hide */ public static final String DEVICE_IN_COMMUNICATION_NAME = "communication"; /** @hide */ public static final String DEVICE_IN_AMBIENT_NAME = "ambient"; @@ -1146,6 +1167,7 @@ public class AudioSystem /** @hide */ public static final String DEVICE_IN_BLUETOOTH_BLE_NAME = "bt_ble"; /** @hide */ public static final String DEVICE_IN_ECHO_REFERENCE_NAME = "echo_reference"; /** @hide */ public static final String DEVICE_IN_HDMI_ARC_NAME = "hdmi_arc"; + /** @hide */ public static final String DEVICE_IN_BLE_HEADSET_NAME = "ble_headset"; /** @hide */ @UnsupportedAppUsage @@ -1208,6 +1230,12 @@ public class AudioSystem return DEVICE_OUT_USB_HEADSET_NAME; case DEVICE_OUT_HEARING_AID: return DEVICE_OUT_HEARING_AID_NAME; + case DEVICE_OUT_ECHO_CANCELLER: + return DEVICE_OUT_ECHO_CANCELLER_NAME; + case DEVICE_OUT_BLE_HEADSET: + return DEVICE_OUT_BLE_HEADSET_NAME; + case DEVICE_OUT_BLE_SPEAKER: + return DEVICE_OUT_BLE_SPEAKER_NAME; case DEVICE_OUT_DEFAULT: default: return Integer.toString(device); @@ -1270,6 +1298,8 @@ public class AudioSystem return DEVICE_IN_ECHO_REFERENCE_NAME; case DEVICE_IN_HDMI_ARC: return DEVICE_IN_HDMI_ARC_NAME; + case DEVICE_IN_BLE_HEADSET: + return DEVICE_IN_BLE_HEADSET_NAME; case DEVICE_IN_DEFAULT: default: return Integer.toString(device); diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java index e959e8e36b42..e1bff03f6833 100644 --- a/media/java/android/media/MediaTranscodeManager.java +++ b/media/java/android/media/MediaTranscodeManager.java @@ -225,13 +225,50 @@ public final class MediaTranscodeManager { job.updateStatusAndResult(TranscodingJob.STATUS_FINISHED, TranscodingJob.RESULT_ERROR); - // Notifies client the job is done. + // Notifies client the job failed. if (job.mListener != null && job.mListenerExecutor != null) { job.mListenerExecutor.execute(() -> job.mListener.onTranscodingFinished(job)); } } } + private void handleTranscodingProgressUpdate(int jobId, int newProgress) { + synchronized (mPendingTranscodingJobs) { + // Gets the job associated with the jobId. + final TranscodingJob job = mPendingTranscodingJobs.get(jobId); + + if (job == null) { + // This should not happen in reality. + Log.e(TAG, "Job " + jobId + " is not in PendingJobs"); + return; + } + + // Updates the job progress. + job.updateProgress(newProgress); + + // Notifies client the progress update. + if (job.mProgressUpdateExecutor != null && job.mProgressUpdateListener != null) { + job.mProgressUpdateExecutor.execute( + () -> job.mProgressUpdateListener.onProgressUpdate(newProgress)); + } + } + } + + private void updateStatus(int jobId, int status) { + synchronized (mPendingTranscodingJobs) { + final TranscodingJob job = mPendingTranscodingJobs.get(jobId); + + if (job == null) { + // This should not happen in reality. + Log.e(TAG, "Job " + jobId + " is not in PendingJobs"); + return; + } + + // Updates the job status. + job.updateStatus(status); + } + } + // Just forwards all the events to the event handler. private ITranscodingClientCallback mTranscodingClientCallback = new ITranscodingClientCallback.Stub() { @@ -263,17 +300,17 @@ public final class MediaTranscodeManager { @Override public void onTranscodingStarted(int jobId) throws RemoteException { - + updateStatus(jobId, TranscodingJob.STATUS_RUNNING); } @Override public void onTranscodingPaused(int jobId) throws RemoteException { - + updateStatus(jobId, TranscodingJob.STATUS_PAUSED); } @Override public void onTranscodingResumed(int jobId) throws RemoteException { - + updateStatus(jobId, TranscodingJob.STATUS_RUNNING); } @Override @@ -294,8 +331,8 @@ public final class MediaTranscodeManager { } @Override - public void onProgressUpdate(int jobId, int progress) throws RemoteException { - //TODO(hkuang): Implement this. + public void onProgressUpdate(int jobId, int newProgress) throws RemoteException { + handleTranscodingProgressUpdate(jobId, newProgress); } }; @@ -661,11 +698,14 @@ public final class MediaTranscodeManager { public static final int STATUS_RUNNING = 2; /** The job is finished. */ public static final int STATUS_FINISHED = 3; + /** The job is paused. */ + public static final int STATUS_PAUSED = 4; @IntDef(prefix = { "STATUS_" }, value = { STATUS_PENDING, STATUS_RUNNING, STATUS_FINISHED, + STATUS_PAUSED, }) @Retention(RetentionPolicy.SOURCE) public @interface Status {} @@ -821,17 +861,12 @@ public final class MediaTranscodeManager { return mResult; } - private void setJobProgress(int newProgress) { - synchronized (this) { - mProgress = newProgress; - } + private synchronized void updateProgress(int newProgress) { + mProgress = newProgress; + } - // Notify listener. - OnProgressUpdateListener onProgressUpdateListener = mProgressUpdateListener; - if (mProgressUpdateListener != null) { - mProgressUpdateExecutor.execute( - () -> onProgressUpdateListener.onProgressUpdate(mProgress)); - } + private synchronized void updateStatus(int newStatus) { + mStatus = newStatus; } } diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java index 3a5e69293a02..8fe10888cab6 100644 --- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java +++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java @@ -33,10 +33,12 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; /* * Functional tests for MediaTranscodeManager in the media framework. @@ -230,5 +232,73 @@ public class MediaTranscodeManagerTest 30, TimeUnit.MILLISECONDS); assertTrue("Fails to cancel transcoding", finishedOnTime); } + + + @Test + public void testTranscodingProgressUpdate() throws Exception { + Log.d(TAG, "Starting: testMediaTranscodeManager"); + + Semaphore transcodeCompleteSemaphore = new Semaphore(0); + final CountDownLatch statusLatch = new CountDownLatch(1); + + // Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4 + // The full path of this file is: + // /data/user/0/com.android.mediatranscodingtest/cache/temp.mp4 + Uri destinationUri = Uri.parse(ContentResolver.SCHEME_FILE + "://" + + mContext.getCacheDir().getAbsolutePath() + "/HevcTranscode.mp4"); + + TranscodingRequest request = + new TranscodingRequest.Builder() + .setSourceUri(mSourceHEVCVideoUri) + .setDestinationUri(destinationUri) + .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO) + .setPriority(MediaTranscodeManager.PRIORITY_REALTIME) + .setVideoTrackFormat(createMediaFormat()) + .build(); + Executor listenerExecutor = Executors.newSingleThreadExecutor(); + + Log.i(TAG, "transcoding to " + createMediaFormat()); + + TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor, + transcodingJob -> { + Log.d(TAG, "Transcoding completed with result: " + transcodingJob.getResult()); + assertEquals(transcodingJob.getResult(), TranscodingJob.RESULT_SUCCESS); + transcodeCompleteSemaphore.release(); + }); + assertNotNull(job); + + AtomicInteger progressUpdateCount = new AtomicInteger(0); + + // Set progress update executor and use the same executor as result listener. + job.setOnProgressUpdateListener(listenerExecutor, + new TranscodingJob.OnProgressUpdateListener() { + int mPreviousProgress = 0; + + @Override + public void onProgressUpdate(int newProgress) { + assertTrue("Invalid proress update", newProgress > mPreviousProgress); + assertTrue("Invalid proress update", newProgress <= 100); + if (newProgress > 0) { + statusLatch.countDown(); + } + mPreviousProgress = newProgress; + progressUpdateCount.getAndIncrement(); + Log.i(TAG, "Get progress update " + newProgress); + } + }); + + try { + statusLatch.await(); + // The transcoding should not be finished yet as the clip is long. + assertTrue("Invalid status", job.getStatus() == TranscodingJob.STATUS_RUNNING); + } catch (InterruptedException e) { } + + Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to cancel."); + boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire( + TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS); + assertTrue("Transcode failed to complete in time.", finishedOnTime); + assertTrue("Failed to receive at least 10 progress updates", + progressUpdateCount.get() > 10); + } } diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index 70ef69d8ce72..0ba7f60c47c3 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -5596,6 +5596,7 @@ package android.app { method public android.graphics.drawable.Icon getIcon(); method public android.app.RemoteInput[] getRemoteInputs(); method public int getSemanticAction(); + method public boolean isAuthenticationRequired(); method public boolean isContextual(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR; @@ -5625,6 +5626,7 @@ package android.app { method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); method @NonNull public android.os.Bundle getExtras(); method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); + method @NonNull public android.app.Notification.Action.Builder setAuthenticationRequired(boolean); method @NonNull public android.app.Notification.Action.Builder setContextual(boolean); method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int); } @@ -24047,6 +24049,8 @@ package android.media { method public boolean isSink(); method public boolean isSource(); field public static final int TYPE_AUX_LINE = 19; // 0x13 + field public static final int TYPE_BLE_HEADSET = 26; // 0x1a + field public static final int TYPE_BLE_SPEAKER = 27; // 0x1b field public static final int TYPE_BLUETOOTH_A2DP = 8; // 0x8 field public static final int TYPE_BLUETOOTH_SCO = 7; // 0x7 field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1 @@ -63863,7 +63867,7 @@ package java.lang.reflect { package java.math { - public class BigDecimal extends java.lang.Number implements java.lang.Comparable<java.math.BigDecimal> java.io.Serializable { + public class BigDecimal extends java.lang.Number implements java.lang.Comparable<java.math.BigDecimal> { ctor public BigDecimal(char[], int, int); ctor public BigDecimal(char[], int, int, java.math.MathContext); ctor public BigDecimal(char[]); @@ -63950,19 +63954,20 @@ package java.math { field public static final java.math.BigDecimal ZERO; } - public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> java.io.Serializable { + public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> { + ctor public BigInteger(byte[]); + ctor public BigInteger(int, byte[]); + ctor public BigInteger(@NonNull String, int); + ctor public BigInteger(@NonNull String); ctor public BigInteger(int, @NonNull java.util.Random); ctor public BigInteger(int, int, @NonNull java.util.Random); - ctor public BigInteger(@NonNull String); - ctor public BigInteger(@NonNull String, int); - ctor public BigInteger(int, byte[]); - ctor public BigInteger(byte[]); method @NonNull public java.math.BigInteger abs(); method @NonNull public java.math.BigInteger add(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger and(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger andNot(@NonNull java.math.BigInteger); method public int bitCount(); method public int bitLength(); + method public byte byteValueExact(); method @NonNull public java.math.BigInteger clearBit(int); method public int compareTo(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger divide(@NonNull java.math.BigInteger); @@ -63973,8 +63978,10 @@ package java.math { method @NonNull public java.math.BigInteger gcd(@NonNull java.math.BigInteger); method public int getLowestSetBit(); method public int intValue(); + method public int intValueExact(); method public boolean isProbablePrime(int); method public long longValue(); + method public long longValueExact(); method @NonNull public java.math.BigInteger max(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger min(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger mod(@NonNull java.math.BigInteger); @@ -63991,6 +63998,7 @@ package java.math { method @NonNull public java.math.BigInteger setBit(int); method @NonNull public java.math.BigInteger shiftLeft(int); method @NonNull public java.math.BigInteger shiftRight(int); + method public short shortValueExact(); method public int signum(); method @NonNull public java.math.BigInteger subtract(@NonNull java.math.BigInteger); method public boolean testBit(int); diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt index 86ac3e477dc4..35b483b9fb84 100644 --- a/non-updatable-api/module-lib-current.txt +++ b/non-updatable-api/module-lib-current.txt @@ -54,6 +54,7 @@ package android.os { } public interface Parcelable { + method public default int getStability(); field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0 field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1 } diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index 4d41fa5e3c4e..dbf9e9fb4ae5 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -301,6 +301,7 @@ package android { field public static final int config_helpIntentNameKey = 17039390; // 0x104001e field public static final int config_helpPackageNameKey = 17039387; // 0x104001b field public static final int config_helpPackageNameValue = 17039388; // 0x104001c + field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028 field public static final int config_systemGallery = 17039399; // 0x1040027 } diff --git a/packages/CarSystemUI/proguard.flags b/packages/CarSystemUI/proguard.flags index 66cbf2650429..516e70f56158 100644 --- a/packages/CarSystemUI/proguard.flags +++ b/packages/CarSystemUI/proguard.flags @@ -1,4 +1,6 @@ -keep class com.android.systemui.CarSystemUIFactory -keep class com.android.car.notification.headsup.animationhelper.** +-keep class com.android.systemui.CarGlobalRootComponent { *; } + -include ../SystemUI/proguard.flags diff --git a/packages/CarSystemUI/samples/sample1/rro/Android.bp b/packages/CarSystemUI/samples/sample1/rro/Android.bp new file mode 100644 index 000000000000..5b0347ff73fd --- /dev/null +++ b/packages/CarSystemUI/samples/sample1/rro/Android.bp @@ -0,0 +1,27 @@ +// +// Copyright (C) 2020 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. +// + +android_app { + name: "CarSystemUISampleOneRRO", + resource_dirs: ["res"], + certificate: "platform", + platform_apis: true, + manifest: "AndroidManifest.xml", + aaptflags: [ + "--no-resource-deduping", + "--no-resource-removal", + ] +}
\ No newline at end of file diff --git a/packages/CarSystemUI/samples/sample1/rro/AndroidManifest.xml b/packages/CarSystemUI/samples/sample1/rro/AndroidManifest.xml new file mode 100644 index 000000000000..5c25056f7915 --- /dev/null +++ b/packages/CarSystemUI/samples/sample1/rro/AndroidManifest.xml @@ -0,0 +1,24 @@ +<!-- + ~ Copyright (C) 2020 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.systemui.rro"> + <overlay + android:targetPackage="com.android.systemui" + android:isStatic="false" + android:resourcesMap="@xml/car_sysui_overlays" + /> +</manifest>
\ No newline at end of file diff --git a/packages/CarSystemUI/samples/sample1/rro/res/values/config.xml b/packages/CarSystemUI/samples/sample1/rro/res/values/config.xml new file mode 100644 index 000000000000..854ab7d7e49b --- /dev/null +++ b/packages/CarSystemUI/samples/sample1/rro/res/values/config.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources> + <!-- Configure which system bars should be displayed. --> + <bool name="config_enableTopNavigationBar">true</bool> + <bool name="config_enableLeftNavigationBar">true</bool> + <bool name="config_enableRightNavigationBar">true</bool> + <bool name="config_enableBottomNavigationBar">true</bool> + + <!-- Configure the type of each system bar. Each system bar must have a unique type. --> + <!-- STATUS_BAR = 0--> + <!-- NAVIGATION_BAR = 1--> + <!-- STATUS_BAR_EXTRA = 2--> + <!-- NAVIGATION_BAR_EXTRA = 3--> + <integer name="config_topSystemBarType">0</integer> + <integer name="config_leftSystemBarType">2</integer> + <integer name="config_rightSystemBarType">3</integer> + <integer name="config_bottomSystemBarType">1</integer> + + <!-- Configure the relative z-order among the system bars. When two system bars overlap (e.g. + if both top bar and left bar are enabled, it creates an overlapping space in the upper left + corner), the system bar with the higher z-order takes the overlapping space and padding is + applied to the other bar.--> + <!-- NOTE: If two overlapping system bars have the same z-order, SystemBarConfigs will throw a + RuntimeException, since their placing order cannot be determined. Bars that do not overlap + are allowed to have the same z-order. --> + <!-- NOTE: If the z-order of a bar is 10 or above, it will also appear on top of HUN's. --> + <integer name="config_topSystemBarZOrder">1</integer> + <integer name="config_leftSystemBarZOrder">0</integer> + <integer name="config_rightSystemBarZOrder">0</integer> + <integer name="config_bottomSystemBarZOrder">10</integer> +</resources>
\ No newline at end of file diff --git a/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml b/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml new file mode 100644 index 000000000000..7bcb8e1b43dd --- /dev/null +++ b/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml @@ -0,0 +1,33 @@ + +<!-- + ~ Copyright (C) 2020 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. + --> + +<overlay> + <item target="bool/config_enableTopNavigationBar" value="@bool/config_enableTopNavigationBar"/> + <item target="bool/config_enableLeftNavigationBar" value="@bool/config_enableLeftNavigationBar"/> + <item target="bool/config_enableRightNavigationBar" value="@bool/config_enableRightNavigationBar"/> + <item target="bool/config_enableBottomNavigationBar" value="@bool/config_enableBottomNavigationBar"/> + + <item target="integer/config_topSystemBarType" value="@integer/config_topSystemBarType"/> + <item target="integer/config_leftSystemBarType" value="@integer/config_leftSystemBarType"/> + <item target="integer/config_rightSystemBarType" value="@integer/config_rightSystemBarType"/> + <item target="integer/config_bottomSystemBarType" value="@integer/config_bottomSystemBarType"/> + + <item target="integer/config_topSystemBarZOrder" value="@integer/config_topSystemBarZOrder"/> + <item target="integer/config_leftSystemBarZOrder" value="@integer/config_leftSystemBarZOrder"/> + <item target="integer/config_rightSystemBarZOrder" value="@integer/config_rightSystemBarZOrder"/> + <item target="integer/config_bottomSystemBarZOrder" value="@integer/config_bottomSystemBarZOrder"/> +</overlay>
\ No newline at end of file diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java index ece3bee000f9..fde0b1a97e46 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java @@ -18,9 +18,9 @@ package com.android.systemui; import com.android.systemui.dagger.DependencyBinder; import com.android.systemui.dagger.DependencyProvider; +import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.SystemServicesModule; import com.android.systemui.dagger.SystemUIModule; -import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.onehanded.dagger.OneHandedModule; import com.android.systemui.pip.phone.dagger.PipModule; @@ -28,6 +28,7 @@ import javax.inject.Singleton; import dagger.Component; +/** Car subclass for GlobalRootComponent. */ @Singleton @Component( modules = { @@ -41,12 +42,15 @@ import dagger.Component; CarSystemUIModule.class, CarSystemUIBinder.class }) -public interface CarSystemUIRootComponent extends SystemUIRootComponent { +public interface CarGlobalRootComponent extends GlobalRootComponent { /** - * Builder for a CarSystemUIRootComponent. + * Builder for a CarGlobalRootComponent. */ @Component.Builder - interface Builder extends SystemUIRootComponent.Builder { - CarSystemUIRootComponent build(); + interface Builder extends GlobalRootComponent.Builder { + CarGlobalRootComponent build(); } + + @Override + CarSysUIComponent.Builder getSysUIComponent(); } diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java new file mode 100644 index 000000000000..d19f368f22b6 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui; + +import com.android.systemui.dagger.SysUIComponent; +import com.android.systemui.dagger.SysUISingleton; + +import dagger.Subcomponent; + +/** + * Dagger Subcomponent for Core SysUI. + */ +@SysUISingleton +@Subcomponent(modules = {}) +public interface CarSysUIComponent extends SysUIComponent { + + /** + * Builder for a CarSysUIComponent. + */ + @Subcomponent.Builder + interface Builder extends SysUIComponent.Builder { + CarSysUIComponent build(); + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java index 03ea9418415d..a65edc5477df 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java @@ -19,7 +19,7 @@ package com.android.systemui; import android.content.Context; import android.content.res.Resources; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; import java.util.HashSet; import java.util.Set; @@ -30,8 +30,8 @@ import java.util.Set; public class CarSystemUIFactory extends SystemUIFactory { @Override - protected SystemUIRootComponent buildSystemUIRootComponent(Context context) { - return DaggerCarSystemUIRootComponent.builder() + protected GlobalRootComponent buildGlobalRootComponent(Context context) { + return DaggerCarGlobalRootComponent.builder() .context(context) .build(); } diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index f4e704ea373e..53dd947a7eff 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -32,7 +32,7 @@ import com.android.systemui.car.keyguard.CarKeyguardViewController; import com.android.systemui.car.statusbar.DozeServiceHost; import com.android.systemui.car.statusbar.DummyNotificationShadeWindowController; import com.android.systemui.car.volume.CarVolumeDialogComponent; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; @@ -79,8 +79,15 @@ import dagger.Binds; import dagger.Module; import dagger.Provides; -@Module(includes = {DividerModule.class, QSModule.class}) -public abstract class CarSystemUIModule { +@Module( + includes = { + DividerModule.class, + QSModule.class + }, + subcomponents = { + CarSysUIComponent.class + }) +abstract class CarSystemUIModule { @Singleton @Provides @@ -188,8 +195,8 @@ public abstract class CarSystemUIModule { abstract ShadeController provideShadeController(ShadeControllerImpl shadeController); @Binds - abstract SystemUIRootComponent bindSystemUIRootComponent( - CarSystemUIRootComponent systemUIRootComponent); + abstract GlobalRootComponent bindGlobalRootComponent( + CarGlobalRootComponent globalRootComponent); @Binds abstract VolumeDialogComponent bindVolumeDialogComponent( diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java index 8efbad64f3d2..2c4545e7b265 100644 --- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java +++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java @@ -155,41 +155,6 @@ public class FusedLocationServiceTest { assertThat(mManager.getNextLocation(TIMEOUT_MS)).isEqualTo(location); } - @Test - public void testBypassRequest() throws Exception { - LocationRequest request = LocationRequest.createFromDeprecatedProvider(FUSED_PROVIDER, 1000, - 0, false).setQuality(LocationRequest.POWER_HIGH).setLocationSettingsIgnored(true); - - mProvider.setRequest( - new ProviderRequest.Builder() - .setInterval(1000) - .setLocationSettingsIgnored(true) - .setLocationRequests(Collections.singletonList(request)) - .build(), - new WorkSource()); - - boolean containsNetworkBypass = false; - for (LocationRequest iRequest : mLocationManager.getTestProviderCurrentRequests( - NETWORK_PROVIDER)) { - if (iRequest.isLocationSettingsIgnored()) { - containsNetworkBypass = true; - break; - } - } - - boolean containsGpsBypass = false; - for (LocationRequest iRequest : mLocationManager.getTestProviderCurrentRequests( - GPS_PROVIDER)) { - if (iRequest.isLocationSettingsIgnored()) { - containsGpsBypass = true; - break; - } - } - - assertThat(containsNetworkBypass).isTrue(); - assertThat(containsGpsBypass).isTrue(); - } - private static class LocationProviderManagerCapture extends ILocationProviderManager.Stub { private final LinkedBlockingQueue<Location> mLocations; diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index ddf2bc0991a4..5f5be97c322c 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -165,7 +165,7 @@ <string name="tts_lang_not_selected" msgid="7927823081096056147">"Langue non sélectionnée"</string> <string name="tts_default_lang_summary" msgid="9042620014800063470">"Définir la langue utilisée par la synthèse vocale"</string> <string name="tts_play_example_title" msgid="1599468547216481684">"Écouter un échantillon"</string> - <string name="tts_play_example_summary" msgid="634044730710636383">"Lire une courte démonstration de la synthèse vocale"</string> + <string name="tts_play_example_summary" msgid="634044730710636383">"Écoutez une courte démonstration de la synthèse vocale"</string> <string name="tts_install_data_title" msgid="1829942496472751703">"Installer les données vocales"</string> <string name="tts_install_data_summary" msgid="3608874324992243851">"Installer les données nécessaires à la synthèse vocale"</string> <string name="tts_engine_security_warning" msgid="3372432853837988146">"Ce moteur de synthèse vocale est susceptible de collecter tout ce qui sera lu, y compris les données personnelles comme les mots de passe et les numéros de carte de paiement. Il provient du moteur <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Voulez-vous activer son utilisation ?"</string> @@ -189,8 +189,8 @@ <item msgid="1158955023692670059">"Rapide"</item> <item msgid="5664310435707146591">"Plus rapide"</item> <item msgid="5491266922147715962">"Très rapide"</item> - <item msgid="7659240015901486196">"Rapide"</item> - <item msgid="7147051179282410945">"Très rapide"</item> + <item msgid="7659240015901486196">"Beaucoup plus rapide"</item> + <item msgid="7147051179282410945">"Extrêmement rapide"</item> <item msgid="581904787661470707">"La plus rapide"</item> </string-array> <string name="choose_profile" msgid="343803890897657450">"Sélectionner un profil"</string> diff --git a/packages/Shell/src/com/android/shell/Screenshooter.java b/packages/Shell/src/com/android/shell/Screenshooter.java index 8e0161961a49..85f25528f07e 100644 --- a/packages/Shell/src/com/android/shell/Screenshooter.java +++ b/packages/Shell/src/com/android/shell/Screenshooter.java @@ -17,11 +17,8 @@ package com.android.shell; import android.graphics.Bitmap; -import android.graphics.Point; -import android.graphics.Rect; -import android.hardware.display.DisplayManagerGlobal; +import android.os.IBinder; import android.util.Log; -import android.view.Display; import android.view.SurfaceControl; /** @@ -40,22 +37,17 @@ final class Screenshooter { * @return The screenshot bitmap on success, null otherwise. */ static Bitmap takeScreenshot() { - Display display = DisplayManagerGlobal.getInstance() - .getRealDisplay(Display.DEFAULT_DISPLAY); - Point displaySize = new Point(); - display.getRealSize(displaySize); - final int displayWidth = displaySize.x; - final int displayHeight = displaySize.y; - - int rotation = display.getRotation(); - Rect crop = new Rect(0, 0, displayWidth, displayHeight); - Log.d(TAG, "Taking screenshot of dimensions " + displayWidth + " x " + displayHeight); + Log.d(TAG, "Taking fullscreen screenshot"); // Take the screenshot - Bitmap screenShot = - SurfaceControl.screenshot(crop, displayWidth, displayHeight, rotation); + final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(displayToken) + .build(); + final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = + SurfaceControl.captureDisplay(captureArgs); + final Bitmap screenShot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); if (screenShot == null) { - Log.e(TAG, "Failed to take screenshot of dimensions " + displayWidth + " x " - + displayHeight); + Log.e(TAG, "Failed to take fullscreen screenshot"); return null; } diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index 14097b12e730..f24215791d1e 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -41,4 +41,6 @@ public <init>(android.content.Context); } --keep class com.android.wm.shell.*
\ No newline at end of file +-keep class com.android.wm.shell.* + +-keep class com.android.systemui.dagger.GlobalRootComponent { *; }
\ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index 53eb2343d26a..401f3e3e0685 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -27,6 +27,7 @@ <item name="android:textColor">?attr/wallpaperTextColorSecondary</item> <item name="android:textSize">14dp</item> <item name="android:background">@drawable/kg_emergency_button_background</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:paddingLeft">12dp</item> <item name="android:paddingRight">12dp</item> </style> diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media.xml b/packages/SystemUI/res/drawable-television/ic_volume_media.xml new file mode 100644 index 000000000000..e43c4b471db4 --- /dev/null +++ b/packages/SystemUI/res/drawable-television/ic_volume_media.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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 + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="@color/tv_volume_dialog_accent" + android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z"/> +</vector> diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml b/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml new file mode 100644 index 000000000000..0f6dc9517f53 --- /dev/null +++ b/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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 + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="@color/tv_volume_dialog_accent" + android:pathData="M3,15V9H7L12,4V20L7,15H3ZM14,7.97C15.48,8.71 16.5,10.23 16.5,12C16.5,13.77 15.48,15.29 14,16.02V7.97Z"/> +</vector> diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml b/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml new file mode 100644 index 000000000000..4b59e13516d2 --- /dev/null +++ b/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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 + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="@color/tv_volume_dialog_accent" + android:pathData="M16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v2.21l2.45,2.45c0.03,-0.2 0.05,-0.41 0.05,-0.63zM19,12c0,0.94 -0.2,1.82 -0.54,2.64l1.51,1.51C20.63,14.91 21,13.5 21,12c0,-4.28 -2.99,-7.86 -7,-8.77v2.06c2.89,0.86 5,3.54 5,6.71zM4.27,3L3,4.27 7.73,9L3,9v6h4l5,5v-6.73l4.25,4.25c-0.67,0.52 -1.42,0.93 -2.25,1.18v2.06c1.38,-0.31 2.63,-0.95 3.69,-1.81L19.73,21 21,19.73l-9,-9L4.27,3zM12,4L9.91,6.09 12,8.18L12,4z"/> +</vector> + diff --git a/packages/SystemUI/res/drawable/ic_volume_media_low.xml b/packages/SystemUI/res/drawable/ic_volume_media_low.xml new file mode 100644 index 000000000000..87591de39d54 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_volume_media_low.xml @@ -0,0 +1,18 @@ +<!-- + Copyright (C) 2020 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/ic_volume_media" /> +</selector> diff --git a/packages/SystemUI/res/drawable/tv_ring_white.xml b/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml index 0f7cc1082f71..93f8724b22a9 100644 --- a/packages/SystemUI/res/drawable/tv_ring_white.xml +++ b/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml @@ -16,10 +16,10 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="oval"> + android:shape="rectangle"> - <stroke - android:width="1dp" - android:color="@android:color/white" /> + <corners android:radius="20dp"/> + <solid android:color="@color/tv_audio_recording_indicator_icon_background"/> + <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/> </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/tv_circle_dark.xml b/packages/SystemUI/res/drawable/tv_volume_dialog_background.xml index d1ba8e71ec31..fee6e57d2e86 100644 --- a/packages/SystemUI/res/drawable/tv_circle_dark.xml +++ b/packages/SystemUI/res/drawable/tv_volume_dialog_background.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - ~ Copyright (C) 2019 The Android Open Source Project + ~ Copyright (C) 2020 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. @@ -16,9 +16,9 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="oval"> + android:shape="rectangle"> - <solid - android:color="@color/tv_audio_recording_indicator_background" /> + <solid android:color="@color/tv_volume_dialog_background" /> + <corners android:radius="@dimen/tv_volume_dialog_corner_radius"/> -</shape>
\ No newline at end of file +</shape> diff --git a/packages/SystemUI/res/drawable/tv_circle_white_translucent.xml b/packages/SystemUI/res/drawable/tv_volume_dialog_circle.xml index 55d21de00ca3..3c4fc05914f8 100644 --- a/packages/SystemUI/res/drawable/tv_circle_white_translucent.xml +++ b/packages/SystemUI/res/drawable/tv_volume_dialog_circle.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - ~ Copyright (C) 2019 The Android Open Source Project + ~ Copyright (C) 2020 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. @@ -17,8 +17,6 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> + <solid android:color="@color/tv_volume_dialog_circle" /> - <solid - android:color="@color/tv_audio_recording_indicator_pulse" /> - -</shape>
\ No newline at end of file +</shape> diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog.xml b/packages/SystemUI/res/layout-land-television/volume_dialog.xml index e0d158d757b3..56d847c6aa2e 100644 --- a/packages/SystemUI/res/layout-land-television/volume_dialog.xml +++ b/packages/SystemUI/res/layout-land-television/volume_dialog.xml @@ -20,7 +20,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/transparent" - android:theme="@style/qs_theme"> + android:theme="@style/volume_dialog_theme"> <FrameLayout android:id="@+id/volume_dialog" @@ -46,7 +46,7 @@ android:translationZ="@dimen/volume_dialog_elevation" android:clipChildren="false" android:clipToPadding="false" - android:background="@drawable/rounded_bg_full"> + android:background="@drawable/tv_volume_dialog_background"> <LinearLayout android:id="@+id/volume_dialog_rows" @@ -54,9 +54,7 @@ android:layout_height="wrap_content" android:minWidth="@dimen/volume_dialog_panel_width" android:gravity="center" - android:orientation="horizontal" - android:paddingRight="@dimen/volume_dialog_stream_padding" - android:paddingLeft="@dimen/volume_dialog_stream_padding"> + android:orientation="horizontal"> <!-- volume rows added and removed here! :-) --> </LinearLayout> @@ -98,4 +96,4 @@ </FrameLayout> -</FrameLayout>
\ No newline at end of file +</FrameLayout> diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml index 08209ab09169..c0f0aa8bbc8d 100644 --- a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml +++ b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml @@ -21,11 +21,12 @@ android:background="@android:color/transparent" android:clipChildren="false" android:clipToPadding="false" - android:theme="@style/qs_theme"> + android:theme="@style/volume_dialog_theme"> <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" + android:padding="@dimen/tv_volume_dialog_row_padding" android:background="@android:color/transparent" android:gravity="center" android:layout_gravity="center" @@ -33,9 +34,9 @@ <com.android.keyguard.AlphaOptimizedImageButton android:id="@+id/volume_row_icon" style="@style/VolumeButtons" - android:layout_width="@dimen/volume_dialog_tap_target_size" - android:layout_height="@dimen/volume_dialog_tap_target_size" - android:background="@drawable/ripple_drawable_20dp" + android:layout_width="@dimen/tv_volume_dialog_bubble_size" + android:layout_height="@dimen/tv_volume_dialog_bubble_size" + android:background="@drawable/tv_volume_dialog_circle" android:tint="@color/accent_tint_color_selector" android:soundEffectsEnabled="false" /> <TextView @@ -62,6 +63,15 @@ android:layout_gravity="center" android:rotation="0" /> </FrameLayout> + <TextView + android:id="@+id/volume_number" + android:layout_width="@dimen/tv_volume_dialog_bubble_size" + android:layout_height="@dimen/tv_volume_dialog_bubble_size" + android:maxLength="2" + android:gravity="center" + android:background="@drawable/tv_volume_dialog_circle" + android:textSize="@dimen/tv_volume_number_text_size" + android:textColor="@color/accent_tint_color_selector"/> </LinearLayout> <include layout="@layout/volume_dnd_icon"/> diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml index 5da7819c3d76..c420117073c5 100644 --- a/packages/SystemUI/res/layout-land/volume_dialog.xml +++ b/packages/SystemUI/res/layout-land/volume_dialog.xml @@ -22,7 +22,7 @@ android:gravity="right" android:layout_gravity="right" android:background="@android:color/transparent" - android:theme="@style/qs_theme"> + android:theme="@style/volume_dialog_theme"> <FrameLayout android:id="@+id/volume_dialog" diff --git a/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml index 1d2340dadb8a..f9336a540376 100644 --- a/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml +++ b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml @@ -19,7 +19,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" - android:padding="32dp"> + android:padding="12dp"> <FrameLayout android:layout_width="wrap_content" @@ -32,45 +32,25 @@ android:orientation="horizontal"> <FrameLayout - android:layout_width="45dp" - android:layout_height="47dp"> + android:layout_width="wrap_content" + android:layout_height="match_parent"> <View android:id="@+id/icon_container_bg" - android:layout_width="match_parent" + android:layout_width="50dp" android:layout_height="match_parent" android:background="@drawable/tv_rect_dark_left_rounded"/> <FrameLayout android:id="@+id/icon_mic" - android:layout_width="35dp" - android:layout_height="35dp" - android:layout_marginStart="6dp" - android:layout_marginTop="6dp" - android:layout_marginBottom="6dp"> - - <View - android:layout_width="27dp" - android:layout_height="27dp" - android:layout_gravity="center" - android:background="@drawable/tv_circle_dark"/> - - <ImageView - android:id="@+id/pulsating_circle" - android:layout_width="27dp" - android:layout_height="27dp" - android:layout_gravity="center" - android:background="@drawable/tv_circle_white_translucent"/> - - <ImageView - android:layout_width="27dp" - android:layout_height="27dp" - android:layout_gravity="center" - android:src="@drawable/tv_ring_white"/> + android:layout_width="34dp" + android:layout_height="24dp" + android:layout_gravity="center" + android:background="@drawable/tv_rect_shadow_rounded"> <ImageView - android:layout_width="16dp" - android:layout_height="16dp" + android:layout_width="13dp" + android:layout_height="13dp" android:layout_gravity="center" android:background="@drawable/tv_ic_mic_white"/> </FrameLayout> diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 7d6547b9cd42..a90b1eb471ff 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -22,7 +22,7 @@ android:gravity="right" android:layout_gravity="right" android:background="@android:color/transparent" - android:theme="@style/qs_theme"> + android:theme="@style/volume_dialog_theme"> <!-- right-aligned to be physically near volume button --> <LinearLayout diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml index 6128da8627a9..b9efc5be70c1 100644 --- a/packages/SystemUI/res/layout/volume_dialog_row.xml +++ b/packages/SystemUI/res/layout/volume_dialog_row.xml @@ -20,7 +20,7 @@ android:layout_width="@dimen/volume_dialog_panel_width" android:clipChildren="false" android:clipToPadding="false" - android:theme="@style/qs_theme"> + android:theme="@style/volume_dialog_theme"> <LinearLayout android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index ee8700261db5..bac915d854d8 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laai tans aanbevelings"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Versteek die huidige sessie."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Versteek"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Maak toe"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Hervat"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 03eb39659ef3..aedbded46298 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ምክሮችን በመጫን ላይ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ሚዲያ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"የአሁኑን ክፍለ-ጊዜ ደብቅ።"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ደብቅ"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ከቆመበት ቀጥል"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ቅንብሮች"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 95d54a2386dd..fee86ca42fe6 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -1093,7 +1093,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"جارٍ تحميل الاقتراحات"</string> <string name="controls_media_title" msgid="1746947284862928133">"الوسائط"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"إخفاء الجلسة الحالية"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"إخفاء"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"استئناف التشغيل"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"الإعدادات"</string> <string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 3023a27b15b4..3778df80197b 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"চুপাৰিছসমূহ ল’ড কৰি থকা হৈছে"</string> <string name="controls_media_title" msgid="1746947284862928133">"মিডিয়া"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"বৰ্তমানৰ ছেশ্বনটো লুকুৱাওক।"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"লুকুৱাওক"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"পুনৰ আৰম্ভ কৰক"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ছেটিংসমূহ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্টো পৰীক্ষা কৰক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 3c8e04b7ba35..874bf7465827 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tövsiyələr yüklənir"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Cari sessiyanı gizlədin."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Gizlədin"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Davam edin"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 4b400eb479c9..2a120c57e955 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavaju se preporuke"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Sakrijte aktuelnu sesiju."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Podešavanja"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index f1064fb7b1d7..e4bb67ae65c6 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загружаюцца рэкамендацыі"</string> <string name="controls_media_title" msgid="1746947284862928133">"Мультымедыя"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Схаваць цяперашні сеанс."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Схаваць"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Узнавіць"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Налады"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 8ba2a1e51769..c51e58ccd6cf 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Препоръките се зареждат"</string> <string name="controls_media_title" msgid="1746947284862928133">"Мултимедия"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Скриване на текущата сесия."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Скриване"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Възобновяване"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 5861c44c1cbb..3d00ca858ef5 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"সাজেশন লোড করা হচ্ছে"</string> <string name="controls_media_title" msgid="1746947284862928133">"মিডিয়া"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"বর্তমান সেশন লুকান।"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"লুকান"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"আবার চালু করুন"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"সেটিংস"</string> <string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string> @@ -1084,8 +1085,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"নতুন কন্ট্রোল দেখতে পাওয়ার বোতাম টিপে ধরে থাকুন"</string> <string name="controls_menu_add" msgid="4447246119229920050">"কন্ট্রোল যোগ করুন"</string> <string name="controls_menu_edit" msgid="890623986951347062">"কন্ট্রোল এডিট করুন"</string> - <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> - <skip /> - <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> - <skip /> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"\'এক হাতে ব্যবহার করার মোড\'-এর ব্যবহার"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"বেরিয়ে আসার জন্য, স্ক্রিনের নিচ থেকে উপরের দিকে সোয়াইপ করুন অথবা অ্যাপের আইকনের উপরে যেকোনও জায়গায় ট্যাপ করুন"</string> </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 984cbebd42eb..14259840d503 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Sakrijte trenutnu sesiju."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index b8c41efa7813..b1501558f924 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregant les recomanacions"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimèdia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Amaga la sessió actual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Amaga"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reprèn"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuració"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index f946cc4f9552..ae6cc13cd1df 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítání doporučení"</string> <string name="controls_media_title" msgid="1746947284862928133">"Média"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Skrýt aktuální relaci."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skrýt"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovat"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavení"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index a6de8a618f23..09f7f1a8762e 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Indlæser anbefalinger"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medie"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Skjul den aktuelle session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skjul"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Genoptag"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Indstillinger"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 372cc1166fce..2410e4785c8d 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Empfehlungen werden geladen"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medien"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Du kannst die aktuelle Sitzung ausblenden."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ausblenden"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Fortsetzen"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Einstellungen"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string> @@ -1084,8 +1085,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Zum Anzeigen der Karten für neue Geräte Ein-/Aus-Taste gedrückt halten"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Steuerelemente hinzufügen"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Steuerelemente bearbeiten"</string> - <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> - <skip /> - <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> - <skip /> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Einhandmodus verwenden"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Wenn du die App schließen möchtest, wische vom unteren Rand des Displays nach oben oder tippe auf eine beliebige Stelle oberhalb der App"</string> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index b4673476bad5..f66c5a88b102 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Φόρτωση προτάσεων"</string> <string name="controls_media_title" msgid="1746947284862928133">"Μέσα"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Απόκρυψη της τρέχουσας περιόδου λειτουργίας."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Απόκρυψη"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Συνέχιση"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ρυθμίσεις"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 7fa7f83c5f12..0e22b583352c 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Hide the current session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index f73dad3a8bef..acf087d51181 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Hide the current session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 7fa7f83c5f12..0e22b583352c 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Hide the current session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 7fa7f83c5f12..0e22b583352c 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Hide the current session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 6140bf1eea3d..4f4238a5eb45 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Hide the current session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 6818116ec9b5..45e072496b25 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string> <string name="controls_media_title" msgid="1746947284862928133">"Contenido multimedia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Oculta la sesión actual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index f09a0d24b26e..f7ebbd02708a 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimedia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ocultar la sesión."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ajustes"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 6236f251f55d..1e5e49e0a143 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Soovituste laadimine"</string> <string name="controls_media_title" msgid="1746947284862928133">"Meedia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Peidetakse praegune seanss."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Peida"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Jätka"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Seaded"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 167a09c71ce3..38b2103d7973 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Gomendioak kargatzen"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimedia-edukia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ezkutatu uneko saioa."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ezkutatu"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Baztertu"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ezarpenak"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string> @@ -1085,5 +1085,5 @@ <string name="controls_menu_add" msgid="4447246119229920050">"Gehitu aukerak"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Editatu aukerak"</string> <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Esku bakarreko modua erabiltzea"</string> - <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Ateratzeko, pasatu hatza pantailaren behealdetik gora edo sakatu aplikazioaren gainean, edonon"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Ateratzeko, pasatu hatza pantailaren behealdetik gora edo sakatu aplikazioaren gainaldea"</string> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 055505200cc2..d39d0c3d5027 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"درحال بار کردن توصیهها"</string> <string name="controls_media_title" msgid="1746947284862928133">"رسانه"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"جلسه فعلی پنهان شود."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"پنهان کردن"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"رد کردن"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ازسرگیری"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"تنظیمات"</string> <string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index ec9bbc4a8929..fa076c4fc40e 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ladataan suosituksia"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Piilota nykyinen käyttökerta."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Piilota"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Jatka"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Asetukset"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 6c5387f63eda..9c418f79a075 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Commandes multimédias"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Masquer la session en cours."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Masquer"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 3a2ae07bc64d..3e2f5fdbff1d 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimédia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Masquer la session en cours."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Masquer"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 25c7b4bfab59..9ecd75e80a4c 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendacións"</string> <string name="controls_media_title" msgid="1746947284862928133">"Contido multimedia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Oculta a sesión actual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 17cc5a45aeb9..6e05a540a13e 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"સુઝાવ લોડ કરી રહ્યાં છીએ"</string> <string name="controls_media_title" msgid="1746947284862928133">"મીડિયા"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"હાલનું સત્ર છુપાવો."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"છુપાવો"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ફરી શરૂ કરો"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"સેટિંગ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string> @@ -1084,8 +1085,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"નવા નિયંત્રણ જોવા માટે પાવર બટનને દબાવી રાખો"</string> <string name="controls_menu_add" msgid="4447246119229920050">"નિયંત્રણો ઉમેરો"</string> <string name="controls_menu_edit" msgid="890623986951347062">"નિયંત્રણોમાં ફેરફાર કરો"</string> - <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> - <skip /> - <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> - <skip /> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"એક-હાથે વાપરો મોડનો ઉપયોગ કરી રહ્યાં છીએ"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"બહાર નીકળવા માટે, સ્ક્રીનની નીચેના ભાગથી ઉપરની તરફ સ્વાઇપ કરો અથવા ઍપના આઇકન પર ગમે ત્યાં ટૅપ કરો"</string> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 97ae7b6e8926..de4fc482a101 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -1071,7 +1071,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सुझाव लोड हो रहे हैं"</string> <string name="controls_media_title" msgid="1746947284862928133">"मीडिया"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"इस मीडिया सेशन को छिपाएं."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"छिपाएं"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"खारिज करें"</string> <string name="controls_media_resume" msgid="1933520684481586053">"फिर से शुरू करें"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग"</string> <string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string> @@ -1086,6 +1086,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"नए कंट्रोल देखने के लिए पावर बटन दबाकर रखें"</string> <string name="controls_menu_add" msgid="4447246119229920050">"कंट्राेल जोड़ें"</string> <string name="controls_menu_edit" msgid="890623986951347062">"कंट्रोल मेन्यू में बदलाव करें"</string> - <string name="one_handed_tutorial_title" msgid="6312198435090726656">"वन-हैंडेड मोड का इस्तेमाल करें"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"वन-हैंडेड मोड का इस्तेमाल करना"</string> <string name="one_handed_tutorial_description" msgid="7674850272340517174">"इसे बंद करने के लिए, स्क्रीन के सबसे निचले हिस्से से ऊपर की ओर स्वाइप करें या ऐप्लिकेशन के आइकॉन के ऊपर कहीं भी टैप करें"</string> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 9e17735ef18d..4bebe79c3c44 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Sakrij trenutačnu sesiju."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 804587f9bdcd..42e251fb39de 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Javaslatok betöltése…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Média"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Jelenlegi munkamenet elrejtése."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Elrejtés"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Folytatás"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Beállítások"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 08ef489901ee..e6b71395c42a 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Բեռնման խորհուրդներ"</string> <string name="controls_media_title" msgid="1746947284862928133">"Մեդիա"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Թաքցրեք ընթացիկ աշխատաշրջանը"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Թաքցնել"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Շարունակել"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Կարգավորումներ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index ba9eca3f0de9..fec4205ba7da 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuat rekomendasi"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Menyembunyikan sesi saat ini."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sembunyikan"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Lanjutkan"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Setelan"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 629581346d46..3a9e63ba9f1a 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Hleður tillögum"</string> <string name="controls_media_title" msgid="1746947284862928133">"Margmiðlunarefni"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Fela núverandi lotu."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fela"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Halda áfram"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Stillingar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index ef862cb0f919..3eca501b103c 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Caricamento dei consigli"</string> <string name="controls_media_title" msgid="1746947284862928133">"Contenuti multimediali"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Nascondi la sessione attuale."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Nascondi"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Riprendi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Impostazioni"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 358946d69472..e88c951cf19e 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"בטעינת המלצות"</string> <string name="controls_media_title" msgid="1746947284862928133">"מדיה"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"הסתרת הסשן הנוכחי."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"הסתרה"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"המשך"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"הגדרות"</string> <string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 9cb872bf1fab..130f682daaf3 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"候補を読み込んでいます"</string> <string name="controls_media_title" msgid="1746947284862928133">"メディア"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"現在のセッションを非表示にします。"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"非表示"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"再開"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index ef6ff128ed09..d050875c35ce 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"მიმდინარეობს რეკომენდაციების ჩატვირთვა"</string> <string name="controls_media_title" msgid="1746947284862928133">"მედია"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"დაიმალოს მიმდინარე სესია"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"დამალვა"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"გაგრძელება"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"პარამეტრები"</string> <string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 08b1f6262f1f..36c726edb791 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Жүктеуге қатысты ұсыныстар"</string> <string name="controls_media_title" msgid="1746947284862928133">"Мультимедиа"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ағымдағы сеансты жасыру"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Жасыру"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Жалғастыру"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Параметрлер"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 6d80ee47413c..9d87c583c007 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"កំពុងផ្ទុកការណែនាំ"</string> <string name="controls_media_title" msgid="1746947284862928133">"មេឌៀ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"លាក់វគ្គបច្ចុប្បន្ន។"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"លាក់"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"បន្ត"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ការកំណត់"</string> <string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើលកម្មវិធី"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index db2086458286..901f024c5f71 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ಶಿಫಾರಸುಗಳು ಲೋಡ್ ಆಗುತ್ತಿವೆ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ಮಾಧ್ಯಮ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ಪ್ರಸ್ತುತ ಸೆಶನ್ ಅನ್ನು ಮರೆಮಾಡಿ."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ಮರೆಮಾಡಿ"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ಪುನರಾರಂಭಿಸಿ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index b43eb410c46d..8a6415566676 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"추천 제어 기능 로드 중"</string> <string name="controls_media_title" msgid="1746947284862928133">"미디어"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"현재 세션을 숨깁니다."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"숨기기"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"다시 시작"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"설정"</string> <string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 02e468a4f311..3cf41264a4d4 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Сунуштар жүктөлүүдө"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Учурдагы сеансты жашыруу."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Жашыруу"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Улантуу"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Жөндөөлөр"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string> diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml index 499341c662b1..90fc652b05e9 100644 --- a/packages/SystemUI/res/values-land-television/dimens.xml +++ b/packages/SystemUI/res/values-land-television/dimens.xml @@ -17,5 +17,8 @@ <resources> <!-- Width of volume bar --> <dimen name="volume_dialog_row_width">252dp</dimen> - <dimen name="volume_dialog_tap_target_size">36dp</dimen> + <dimen name="tv_volume_dialog_bubble_size">36dp</dimen> + <dimen name="tv_volume_dialog_corner_radius">40dp</dimen> + <dimen name="tv_volume_dialog_row_padding">5dp</dimen> + <dimen name="tv_volume_number_text_size">16dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 030bdc1ae120..b1c5a5cd887e 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ກຳລັງໂຫຼດຄຳແນະນຳ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ມີເດຍ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ເຊື່ອງເຊດຊັນປັດຈຸບັນ."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ເຊື່ອງ"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ສືບຕໍ່"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ການຕັ້ງຄ່າ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 6f487416b322..4e9b802f4916 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Įkeliamos rekomendacijos"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medija"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Slėpti dabartinį seansą."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Slėpti"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Tęsti"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nustatymai"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index bdea26a1a202..a4c4666fafe3 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Notiek ieteikumu ielāde"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multivide"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Paslēpiet pašreizējo sesiju."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Paslēpt"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Atsākt"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Iestatījumi"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index c9f3777c6192..7e623ad5032f 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Се вчитуваат препораки"</string> <string name="controls_media_title" msgid="1746947284862928133">"Аудиовизуелни содржини"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Сокриј ја тековнава сесија."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Сокриј"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Продолжи"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Поставки"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index c968c2827437..35e642769981 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"നിർദ്ദേശങ്ങൾ ലോഡ് ചെയ്യുന്നു"</string> <string name="controls_media_title" msgid="1746947284862928133">"മീഡിയ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"നിലവിലെ സെഷൻ മറയ്ക്കുക."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"മറയ്ക്കുക"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"പുനരാരംഭിക്കുക"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ക്രമീകരണം"</string> <string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 9ce6779e9ae4..b4690d418480 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Зөвлөмжүүдийг ачаалж байна"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Одоогийн харилцан үйлдлийг нуугаарай."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Нуух"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Үргэлжлүүлэх"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Тохиргоо"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index d7126795089f..4ea965ad80fc 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"शिफारशी लोड करत आहे"</string> <string name="controls_media_title" msgid="1746947284862928133">"मीडिया"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"सध्याचे सेशन लपवा."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"लपवा"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"पुन्हा सुरू करा"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग्ज"</string> <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 01e918ade0ee..38ee25c7f3e4 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuatkan cadangan"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Sembunyikan sesi semasa."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sembunyikan"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Sambung semula"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Tetapan"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 23b0a06cca8f..150ed94eec38 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"အကြံပြုချက်များ ဖွင့်နေသည်"</string> <string name="controls_media_title" msgid="1746947284862928133">"မီဒီယာ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"လက်ရှိ စက်ရှင်ကို ဖျောက်ထားမည်။"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ဖျောက်ထားမည်"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ပယ်ရန်"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ဆက်လုပ်ရန်"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ဆက်တင်များ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index b0a593fe42f9..d872a89880c9 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laster inn anbefalinger"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medier"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Skjul den nåværende økten."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skjul"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Gjenoppta"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Innstillinger"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 09462cf3ffcb..1974e8088971 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -731,11 +731,11 @@ <string name="see_more_title" msgid="7409317011708185729">"थप हेर्नुहोस्"</string> <string name="appops_camera" msgid="5215967620896725715">"यो अनुप्रयोगले क्यामेराको प्रयोग गर्दै छ।"</string> <string name="appops_microphone" msgid="8805468338613070149">"यो अनुप्रयोगले माइक्रोफोनको प्रयोग गर्दै छ।"</string> - <string name="appops_overlay" msgid="4822261562576558490">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमाथि प्रदर्शन गर्दै छ।"</string> + <string name="appops_overlay" msgid="4822261562576558490">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य एपमाथि प्रदर्शन गर्दै छ।"</string> <string name="appops_camera_mic" msgid="7032239823944420431">"यो अनुप्रयोगले माइक्रोफोन र क्यामेराको प्रयोग गर्दै छ।"</string> - <string name="appops_camera_overlay" msgid="6466845606058816484">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमाथि प्रदर्शन गर्नुका साथै क्यामेराको प्रयोग गर्दै छ।"</string> - <string name="appops_mic_overlay" msgid="4609326508944233061">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमाथि प्रदर्शन गर्नुका साथै माइक्रोफोनको प्रयोग गर्दै छ।"</string> - <string name="appops_camera_mic_overlay" msgid="5584311236445644095">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमाथि प्रदर्शन गर्नुका साथै माइक्रोफोन र क्यामेराको प्रयोग गर्दै छ।"</string> + <string name="appops_camera_overlay" msgid="6466845606058816484">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य एपमाथि प्रदर्शन गर्नुका साथै क्यामेराको प्रयोग गर्दै छ।"</string> + <string name="appops_mic_overlay" msgid="4609326508944233061">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य एपमाथि प्रदर्शन गर्नुका साथै माइक्रोफोनको प्रयोग गर्दै छ।"</string> + <string name="appops_camera_mic_overlay" msgid="5584311236445644095">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य एपमाथि प्रदर्शन गर्नुका साथै माइक्रोफोन र क्यामेराको प्रयोग गर्दै छ।"</string> <string name="notification_appops_settings" msgid="5208974858340445174">"सेटिङहरू"</string> <string name="notification_appops_ok" msgid="2177609375872784124">"ठिक छ"</string> <string name="feedback_silenced" msgid="5382212321253328247">"सिस्टमले यो सूचना आउँदा बज्ने ध्वनि बन्द गरेको छ।"</string> @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सिफारिसहरू लोड गर्दै"</string> <string name="controls_media_title" msgid="1746947284862928133">"मिडिया"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"हालको सत्र लुकाउनुहोस्।"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"लुकाउनुहोस्"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"सुचारु गर्नुहोस्"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिङ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string> @@ -1084,8 +1085,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"नयाँ नियन्त्रण सुविधाहरू हेर्न पावर बटन थिचिराख्नुहोस्"</string> <string name="controls_menu_add" msgid="4447246119229920050">"नियन्त्रण सुविधाहरू थप्नुहोस्"</string> <string name="controls_menu_edit" msgid="890623986951347062">"नियन्त्रण सुविधाहरू सम्पादन गर्नु…"</string> - <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> - <skip /> - <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> - <skip /> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"एक हाते मोड प्रयोग गरिँदै छ"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"बाहिर निस्कन, स्क्रिनको पुछारबाट माथितिर स्वाइप गर्नुहोस् वा एपभन्दा माथि जुनसुकै ठाउँमा ट्याप गर्नुहोस्"</string> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 2385017a0df7..9da8afa4d698 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Aanbevelingen laden"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"De huidige sessie verbergen."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Verbergen"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Hervatten"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellingen"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index d5c077b3ec1b..5b5cbc62fe21 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ସୁପାରିଶଗୁଡ଼ିକ ଲୋଡ୍ କରାଯାଉଛି"</string> <string name="controls_media_title" msgid="1746947284862928133">"ମିଡିଆ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ବର୍ତ୍ତମାନର ସେସନ୍ ଲୁଚାନ୍ତୁ।"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ଲୁଚାନ୍ତୁ"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ସେଟିଂସ୍"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string> @@ -1084,8 +1085,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"ନୂଆ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ ପାୱାର ବଟନକୁ ଧରି ରଖନ୍ତୁ"</string> <string name="controls_menu_add" msgid="4447246119229920050">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରନ୍ତୁ"</string> <string name="controls_menu_edit" msgid="890623986951347062">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ସମ୍ପାଦନ କରନ୍ତୁ"</string> - <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> - <skip /> - <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> - <skip /> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ଏକ-ହାତ ମୋଡ୍ ବ୍ୟବହାର କରି"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ବାହାରି ଯିବା ପାଇଁ, ତଳୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ କିମ୍ବା ଆପ୍ ଆଇକନର ଉପରେ ଯେ କୌଣସି ସ୍ଥାନରେ ଟାପ୍ କରନ୍ତୁ"</string> </resources> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 11567821397a..5c31ce71ef98 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ਸਿਫ਼ਾਰਸ਼ਾਂ ਲੋਡ ਹੋ ਰਹੀਆਂ ਹਨ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ਮੀਡੀਆ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ਮੌਜੂਦਾ ਸੈਸ਼ਨ ਨੂੰ ਲੁਕਾਓ।"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ਲੁਕਾਓ"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ਸੈਟਿੰਗਾਂ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string> @@ -1084,8 +1085,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"ਨਵੇਂ ਕੰਟਰੋਲ ਦੇਖਣ ਲਈ ਪਾਵਰ ਬਟਨ ਦਬਾਈ ਰੱਖੋ"</string> <string name="controls_menu_add" msgid="4447246119229920050">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string> <string name="controls_menu_edit" msgid="890623986951347062">"ਕੰਟਰੋਲਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string> - <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> - <skip /> - <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> - <skip /> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ਇੱਕ ਹੱਥ ਮੋਡ ਵਰਤਣਾ"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ਬਾਹਰ ਜਾਣ ਲਈ, ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ ਜਾਂ ਐਪ \'ਤੇ ਕਿਤੇ ਵੀ ਟੈਪ ਕਰੋ"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 1f6effe431e7..b7ee75057626 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Wczytuję rekomendacje"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimedia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ukryj bieżącą sesję."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ukryj"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Wznów"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ustawienia"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 14d7a84dab28..715b0e45faeb 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mídia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ocultar a sessão atual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dispensar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index a6f7f004f411..1a59de496c91 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"A carregar recomendações…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimédia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Oculte a sessão atual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignorar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Definições"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 14d7a84dab28..715b0e45faeb 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mídia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ocultar a sessão atual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dispensar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 0f15cfcd23f6..49c3ba0c2cd8 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Se încarcă recomandările"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ascunde sesiunea actuală."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ascunde"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reia"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Setări"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 6196f88a7bfb..7fb456d5f425 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загрузка рекомендаций…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Скрыть текущий сеанс?"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Скрыть"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Возобновить"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 8aca9f4e0dbd..1cd1ceb21c97 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"නිර්දේශ පූරණය කරමින්"</string> <string name="controls_media_title" msgid="1746947284862928133">"මාධ්ය"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"වත්මන් සැසිය සඟවන්න."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"සඟවන්න"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ඉවත ලන්න"</string> <string name="controls_media_resume" msgid="1933520684481586053">"නැවත පටන් ගන්න"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"සැකසීම්"</string> <string name="controls_error_timeout" msgid="794197289772728958">"අක්රියයි, යෙදුම පරීක්ෂා කරන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 45ee562b374c..9d7e7d1cd27c 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítavajú sa odporúčania"</string> <string name="controls_media_title" msgid="1746947284862928133">"Médiá"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Skryť aktuálnu reláciu."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skryť"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovať"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavenia"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index c7ad8ab92da3..ecbf1d905e5b 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nalaganje priporočil"</string> <string name="controls_media_title" msgid="1746947284862928133">"Predstavnost"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Skrije trenutno sejo."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skrij"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Nadaljuj"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavitve"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 3e0aecc16d4e..70245b875726 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Po ngarkon rekomandimet"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Fshih sesionin aktual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fshih"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Vazhdo"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Cilësimet"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 985041b3b24d..1d02ca6ab455 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Учитавају се препоруке"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медији"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Сакријте актуелну сесију."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Сакриј"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Настави"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Подешавања"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 2018a383b5ed..7a7448be16c5 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Rekommendationer läses in"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Dölj den aktuella sessionen."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Dölj"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Återuppta"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Inställningar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 6eecc0e402fa..b8d95fcd0c1a 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Inapakia mapendekezo"</string> <string name="controls_media_title" msgid="1746947284862928133">"Maudhui"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ficha kipindi cha sasa."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ficha"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Endelea"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Mipangilio"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index a05e0e735620..60c1cf9dcac0 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"பரிந்துரைகளை ஏற்றுகிறது"</string> <string name="controls_media_title" msgid="1746947284862928133">"மீடியா"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"இந்த அமர்வை மறையுங்கள்."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"மறை"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"தொடர்க"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"அமைப்புகள்"</string> <string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 7d76abd0f20f..6cfe03d95023 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"సిఫార్సులు లోడ్ అవుతున్నాయి"</string> <string name="controls_media_title" msgid="1746947284862928133">"మీడియా"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ప్రస్తుత సెషన్ను దాచు."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"దాచు"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"కొనసాగించండి"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"సెట్టింగ్లు"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ఇన్యాక్టివ్, యాప్ చెక్ చేయండి"</string> diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml index 1696aab66148..7b1479acc35e 100644 --- a/packages/SystemUI/res/values-television/config.xml +++ b/packages/SystemUI/res/values-television/config.xml @@ -43,4 +43,7 @@ <item>com.android.systemui.toast.ToastUI</item> <item>com.android.systemui.onehanded.OneHandedUI</item> </string-array> + + <!-- Show a separate icon for low and high volume on the volume dialog --> + <bool name="config_showLowMediaVolumeIcon">true</bool> </resources> diff --git a/packages/SystemUI/res/values-television/styles.xml b/packages/SystemUI/res/values-television/styles.xml index b01c5d88e3b3..4cf7034a29bf 100644 --- a/packages/SystemUI/res/values-television/styles.xml +++ b/packages/SystemUI/res/values-television/styles.xml @@ -22,4 +22,8 @@ <item name="android:windowEnterAnimation">@null</item> <item name="android:windowExitAnimation">@null</item> </style> + + <style name="volume_dialog_theme" parent="qs_theme"> + <item name="android:colorAccent">@color/tv_volume_dialog_accent</item> + </style> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 765c22424e89..a2c1127df5ca 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"กำลังโหลดคำแนะนำ"</string> <string name="controls_media_title" msgid="1746947284862928133">"สื่อ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ซ่อนเซสชันปัจจุบัน"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ซ่อน"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"เล่นต่อ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"การตั้งค่า"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index c2cae9024a60..e5f0532b0e7b 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nilo-load ang rekomendasyon"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Itago ang kasalukuyang session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Itago"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Ituloy"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Mga Setting"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 74b44f2079c6..4943e2d03920 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Öneriler yükleniyor"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medya"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Mevcut oturumu gizle."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Gizle"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Devam ettir"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 38c331ade344..447912e08835 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Завантаження рекомендацій"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медіа"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Приховати поточний сеанс."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Приховати"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Відновити"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Налаштування"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 69ddabbe94ac..20b551882344 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"تجاویز لوڈ ہو رہی ہیں"</string> <string name="controls_media_title" msgid="1746947284862928133">"میڈیا"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"موجودہ سیشن چھپائیں۔"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"چھپائیں"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"دوبارہ شروع کریں"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ترتیبات"</string> <string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index ed704b0f5597..cf1da7508052 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -227,7 +227,7 @@ <string name="data_connection_roaming" msgid="375650836665414797">"Rouming"</string> <string name="data_connection_edge" msgid="6316755666481405762">"EDGE"</string> <string name="accessibility_data_connection_wifi" msgid="4422160347472742434">"Wi-Fi"</string> - <string name="accessibility_no_sim" msgid="1140839832913084973">"SIM karta solinmagan."</string> + <string name="accessibility_no_sim" msgid="1140839832913084973">"SIM kartasiz."</string> <string name="accessibility_cell_data" msgid="172950885786007392">"Mobil internet"</string> <string name="accessibility_cell_data_on" msgid="691666434519443162">"Mobil internet yoniq"</string> <string name="cell_data_off_content_description" msgid="9165555931499878044">"Mobil internet yoqilmagan"</string> @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tavsiyalar yuklanmoqda"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Joriy seans berkitilsin."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Berkitish"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Yopish"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Davom etish"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Sozlamalar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 5cc209941771..a12a08d0a1e6 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Đang tải các đề xuất"</string> <string name="controls_media_title" msgid="1746947284862928133">"Nội dung nghe nhìn"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ẩn phiên hiện tại."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ẩn"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Tiếp tục"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Cài đặt"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index f670bf682b64..3382365b7ccb 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在加载推荐内容"</string> <string name="controls_media_title" msgid="1746947284862928133">"媒体"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"隐藏当前会话。"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隐藏"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"继续播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"设置"</string> <string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 2e26d6153a8f..1d55ca22a43f 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議"</string> <string name="controls_media_title" msgid="1746947284862928133">"媒體"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"隱藏目前的工作階段。"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隱藏"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 0049d2ec1f56..e62c164684b3 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議控制項"</string> <string name="controls_media_title" msgid="1746947284862928133">"媒體"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"隱藏目前的工作階段。"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隱藏"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index c8c99b1c18c1..bd7391203dd8 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ilayisha izincomo"</string> <string name="controls_media_title" msgid="1746947284862928133">"Imidiya"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Fihla iseshini yamanje."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fihla"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Qalisa kabusha"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Izilungiselelo"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string> diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml index 53cd9716c98e..cb49918e4e3f 100644 --- a/packages/SystemUI/res/values/colors_tv.xml +++ b/packages/SystemUI/res/values/colors_tv.xml @@ -24,7 +24,11 @@ <!-- Background color for audio recording indicator (G800) --> <color name="tv_audio_recording_indicator_background">#FF3C4043</color> - <color name="tv_audio_recording_indicator_pulse">#4DFFFFFF</color> + <color name="tv_audio_recording_indicator_icon_background">#CC000000</color> + <color name="tv_audio_recording_indicator_stroke">#33FFFFFF</color> <color name="red">#FFCC0000</color> + <color name="tv_volume_dialog_background">#E61F232B</color> + <color name="tv_volume_dialog_circle">#08FFFFFF</color> + <color name="tv_volume_dialog_accent">#FFDADCE0</color> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index fba43a628387..ce1ca5ad1723 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -565,13 +565,9 @@ <!-- If the config font scale is >= this value, potentially adjust the number of columns--> <item name="controls_max_columns_adjust_above_font_scale" translatable="false" format="float" type="dimen">1.25</item> - <!-- One handed mode default offset % of display size --> - <fraction name="config_one_handed_offset">50%</fraction> - <!-- Allow one handed to enable round corner --> <bool name="config_one_handed_enable_round_corner">true</bool> - <!-- Animation duration for translating of one handed when trigger / dismiss. --> - <integer name="config_one_handed_translate_animation_duration">150</integer> - + <!-- Show a separate icon for low and high volume on the volume dialog --> + <bool name="config_showLowMediaVolumeIcon">false</bool> </resources> diff --git a/packages/SystemUI/res/values/donottranslate.xml b/packages/SystemUI/res/values/donottranslate.xml index a1c52e55082a..f05be066d2e2 100644 --- a/packages/SystemUI/res/values/donottranslate.xml +++ b/packages/SystemUI/res/values/donottranslate.xml @@ -21,5 +21,5 @@ <string name="system_ui_date_pattern" translatable="false">@*android:string/system_ui_date_pattern</string> <!-- Date format for the always on display. --> - <item type="string" name="system_ui_aod_date_pattern" translatable="false">@*android:string/system_ui_date_pattern</item> + <item type="string" name="system_ui_aod_date_pattern" translatable="false">EEEMMMd</item> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 9e5b94ee855c..ee07e613a0c5 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -387,6 +387,9 @@ <item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item> </style> + <!-- Overridden by values-television/styles.xml with tv-specific settings --> + <style name="volume_dialog_theme" parent="qs_theme"/> + <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light"> <item name="android:colorAccent">@color/remote_input_accent</item> </style> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java new file mode 100644 index 000000000000..1de740a083c2 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shared.system; + +import android.annotation.UserIdInt; +import android.content.Context; + +public class ContextUtils { + + /** Get the user associated with this context */ + public static @UserIdInt int getUserId(Context context) { + return context.getUserId(); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 1db2e32b8cdb..5f00a591860e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -256,7 +256,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y); mInjectionInflationController = new InjectionInflationController( - SystemUIFactory.getInstance().getRootComponent()); + SystemUIFactory.getInstance().getRootComponent().createViewInstanceCreatorFactory()); mViewConfiguration = ViewConfiguration.get(context); mKeyguardStateController = Dependency.get(KeyguardStateController.class); mSecondaryLockScreenController = new AdminSecondaryLockScreenController(context, this, diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 449ed8c3bcdb..2365f128532e 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -16,6 +16,7 @@ package com.android.systemui; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; +import android.annotation.Nullable; import android.app.Activity; import android.app.AlertDialog; import android.app.slice.SliceManager; @@ -29,6 +30,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; import android.text.BidiFormatter; +import android.util.EventLog; import android.util.Log; import android.widget.CheckBox; import android.widget.TextView; @@ -50,10 +52,17 @@ public class SlicePermissionActivity extends Activity implements OnClickListener mUri = getIntent().getParcelableExtra(SliceProvider.EXTRA_BIND_URI); mCallingPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PKG); - mProviderPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); + if (mUri == null) { + Log.e(TAG, SliceProvider.EXTRA_BIND_URI + " wasn't provided"); + finish(); + return; + } try { PackageManager pm = getPackageManager(); + mProviderPkg = pm.resolveContentProvider(mUri.getAuthority(), + PackageManager.GET_META_DATA).applicationInfo.packageName; + verifyCallingPkg(); CharSequence app1 = BidiFormatter.getInstance().unicodeWrap(pm.getApplicationInfo( mCallingPkg, 0).loadSafeLabel(pm, PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, PackageItemInfo.SAFE_LABEL_FLAG_TRIM @@ -97,4 +106,29 @@ public class SlicePermissionActivity extends Activity implements OnClickListener public void onDismiss(DialogInterface dialog) { finish(); } + + private void verifyCallingPkg() { + final String providerPkg = getIntent().getStringExtra("provider_pkg"); + if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; + final String callingPkg = getCallingPkg(); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format( + "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s", + callingPkg, providerPkg, mProviderPkg, mCallingPkg)); + } + + @Nullable + private String getCallingPkg() { + final Uri referrer = getReferrer(); + if (referrer == null) return null; + return referrer.getHost(); + } + + private int getUid(@Nullable final String pkg) { + if (pkg == null) return -1; + try { + return getPackageManager().getApplicationInfo(pkg, 0).uid; + } catch (NameNotFoundException e) { + } + return -1; + } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java index cacbf969e562..627f5592e667 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java @@ -29,6 +29,10 @@ import androidx.annotation.Nullable; import androidx.core.app.AppComponentFactory; import com.android.systemui.dagger.ContextComponentHelper; +import com.android.systemui.dagger.GlobalRootComponent; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import javax.inject.Inject; @@ -81,8 +85,17 @@ public class SystemUIAppComponentFactory extends AppComponentFactory { ((ContextInitializer) contentProvider).setContextAvailableCallback( context -> { SystemUIFactory.createFromConfig(context); - SystemUIFactory.getInstance().getRootComponent().inject( - contentProvider); + GlobalRootComponent rootComponent = + SystemUIFactory.getInstance().getRootComponent(); + try { + Method injectMethod = rootComponent.getClass() + .getMethod("inject", contentProvider.getClass()); + injectMethod.invoke(rootComponent, contentProvider); + } catch (NoSuchMethodException + | IllegalAccessException + | InvocationTargetException e) { + // no-op + } } ); } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index c84701c9512e..4f78f65f0121 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -32,7 +32,7 @@ import android.util.Log; import android.util.TimingsTraceLog; import com.android.systemui.dagger.ContextComponentHelper; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dump.DumpManager; import com.android.systemui.util.NotificationChannels; @@ -57,7 +57,7 @@ public class SystemUIApplication extends Application implements private SystemUI[] mServices; private boolean mServicesStarted; private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback; - private SystemUIRootComponent mRootComponent; + private GlobalRootComponent mRootComponent; public SystemUIApplication() { super(); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index 1a15c0aae8c1..d987ad3b218d 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -28,8 +28,10 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.bubbles.BubbleController; -import com.android.systemui.dagger.DaggerSystemUIRootComponent; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.DaggerGlobalRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; +import com.android.systemui.dagger.SysUIComponent; +import com.android.systemui.dagger.WMComponent; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -53,7 +55,9 @@ public class SystemUIFactory { private static final String TAG = "SystemUIFactory"; static SystemUIFactory mFactory; - private SystemUIRootComponent mRootComponent; + private GlobalRootComponent mRootComponent; + private WMComponent mWMComponent; + private SysUIComponent mSysUIComponent; public static <T extends SystemUIFactory> T getInstance() { return (T) mFactory; @@ -88,7 +92,10 @@ public class SystemUIFactory { public SystemUIFactory() {} private void init(Context context) { - mRootComponent = buildSystemUIRootComponent(context); + mRootComponent = buildGlobalRootComponent(context); + mWMComponent = mRootComponent.getWMComponentBuilder().build(); + // TODO: use WMComponent to pass APIs into the SysUIComponent. + mSysUIComponent = mRootComponent.getSysUIComponent().build(); // Every other part of our codebase currently relies on Dependency, so we // really need to ensure the Dependency gets initialized early on. @@ -96,13 +103,13 @@ public class SystemUIFactory { dependency.start(); } - protected SystemUIRootComponent buildSystemUIRootComponent(Context context) { - return DaggerSystemUIRootComponent.builder() + protected GlobalRootComponent buildGlobalRootComponent(Context context) { + return DaggerGlobalRootComponent.builder() .context(context) .build(); } - public SystemUIRootComponent getRootComponent() { + public GlobalRootComponent getRootComponent() { return mRootComponent; } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java index 816bcf8f274b..d5f74a86fd94 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java @@ -53,8 +53,8 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_ORIENTATION; @VisibleForTesting - protected WindowMagnificationController mWindowMagnificationController; - protected final ModeSwitchesController mModeSwitchesController; + protected WindowMagnificationAnimationController mWindowMagnificationAnimationController; + private final ModeSwitchesController mModeSwitchesController; private final Handler mHandler; private final AccessibilityManager mAccessibilityManager; private final CommandQueue mCommandQueue; @@ -72,6 +72,11 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall Context.ACCESSIBILITY_SERVICE); mCommandQueue = commandQueue; mModeSwitchesController = modeSwitchesController; + final WindowMagnificationController controller = new WindowMagnificationController(mContext, + mHandler, new SfVsyncFrameCallbackProvider(), null, + new SurfaceControl.Transaction(), this); + mWindowMagnificationAnimationController = new WindowMagnificationAnimationController( + mContext, controller); } @Override @@ -81,9 +86,7 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall return; } mLastConfiguration.setTo(newConfig); - if (mWindowMagnificationController != null) { - mWindowMagnificationController.onConfigurationChanged(configDiff); - } + mWindowMagnificationAnimationController.onConfigurationChanged(configDiff); if (mModeSwitchesController != null) { mModeSwitchesController.onConfigurationChanged(configDiff); } @@ -97,39 +100,25 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall @MainThread void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) { //TODO: b/144080869 support multi-display. - if (mWindowMagnificationController == null) { - mWindowMagnificationController = new WindowMagnificationController(mContext, - mHandler, - new SfVsyncFrameCallbackProvider(), - null, new SurfaceControl.Transaction(), - this); - } - mWindowMagnificationController.enableWindowMagnification(scale, centerX, centerY); + mWindowMagnificationAnimationController.enableWindowMagnification(scale, centerX, centerY); } @MainThread void setScale(int displayId, float scale) { //TODO: b/144080869 support multi-display. - if (mWindowMagnificationController != null) { - mWindowMagnificationController.setScale(scale); - } + mWindowMagnificationAnimationController.setScale(scale); } @MainThread void moveWindowMagnifier(int displayId, float offsetX, float offsetY) { //TODO: b/144080869 support multi-display. - if (mWindowMagnificationController != null) { - mWindowMagnificationController.moveWindowMagnifier(offsetX, offsetY); - } + mWindowMagnificationAnimationController.moveWindowMagnifier(offsetX, offsetY); } @MainThread void disableWindowMagnification(int displayId) { //TODO: b/144080869 support multi-display. - if (mWindowMagnificationController != null) { - mWindowMagnificationController.deleteWindowMagnification(); - } - mWindowMagnificationController = null; + mWindowMagnificationAnimationController.deleteWindowMagnification(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java new file mode 100644 index 000000000000..ae51623f3dc2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility; + +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.annotation.IntDef; +import android.content.Context; +import android.content.res.Resources; +import android.util.Log; +import android.view.animation.AccelerateInterpolator; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.R; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Provides same functionality of {@link WindowMagnificationController}. Some methods run with + * the animation. + */ +class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUpdateListener, + Animator.AnimatorListener { + + private static final String TAG = "WindowMagnificationBridge"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + @Retention(RetentionPolicy.SOURCE) + @IntDef({STATE_DISABLED, STATE_ENABLED, STATE_DISABLING, STATE_ENABLING}) + @interface MagnificationState {} + + //The window magnification is disabled. + private static final int STATE_DISABLED = 0; + //The window magnification is enabled. + private static final int STATE_ENABLED = 1; + //The window magnification is going to be disabled when the animation is end. + private static final int STATE_DISABLING = 2; + //The animation is running for enabling the window magnification. + private static final int STATE_ENABLING = 3; + + private final WindowMagnificationController mController; + private final ValueAnimator mValueAnimator; + private final AnimationSpec mStartSpec = new AnimationSpec(); + private final AnimationSpec mEndSpec = new AnimationSpec(); + private final Context mContext; + + @MagnificationState + private int mState = STATE_DISABLED; + + WindowMagnificationAnimationController( + Context context, WindowMagnificationController controller) { + this(context, controller, newValueAnimator(context.getResources())); + } + + @VisibleForTesting + WindowMagnificationAnimationController(Context context, + WindowMagnificationController controller, ValueAnimator valueAnimator) { + mContext = context; + mController = controller; + mValueAnimator = valueAnimator; + mValueAnimator.addUpdateListener(this); + mValueAnimator.addListener(this); + } + + /** + * Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)} + * with transition animation. If the window magnification is not enabled, the scale will start + * from 1.0 and the center won't be changed during the animation. If {@link #mState} is + * {@code STATE_DISABLING}, the animation runs in reverse. + * + * @param scale the target scale, or {@link Float#NaN} to leave unchanged. + * @param centerX the screen-relative X coordinate around which to center, + * or {@link Float#NaN} to leave unchanged. + * @param centerY the screen-relative Y coordinate around which to center, + * or {@link Float#NaN} to leave unchanged. + * + * @see #onAnimationUpdate(ValueAnimator) + */ + void enableWindowMagnification(float scale, float centerX, float centerY) { + if (mState == STATE_ENABLING) { + mValueAnimator.cancel(); + } + setupEnableAnimationSpecs(scale, centerX, centerY); + + if (mEndSpec.equals(mStartSpec)) { + setState(STATE_ENABLED); + } else { + if (mState == STATE_DISABLING) { + mValueAnimator.reverse(); + } else { + mValueAnimator.start(); + } + setState(STATE_ENABLING); + } + } + + private void setupEnableAnimationSpecs(float scale, float centerX, float centerY) { + final float currentScale = mController.getScale(); + final float currentCenterX = mController.getCenterX(); + final float currentCenterY = mController.getCenterY(); + + if (mState == STATE_DISABLED) { + //We don't need to offset the center during the animation. + mStartSpec.set(/* scale*/ 1.0f, centerX, centerY); + mEndSpec.set(Float.isNaN(scale) ? mContext.getResources().getInteger( + R.integer.magnification_default_scale) : scale, centerX, centerY); + } else { + mStartSpec.set(currentScale, currentCenterX, currentCenterY); + mEndSpec.set(Float.isNaN(scale) ? currentScale : scale, + Float.isNaN(centerX) ? currentCenterX : centerX, + Float.isNaN(centerY) ? currentCenterY : centerY); + } + if (DEBUG) { + Log.d(TAG, "SetupEnableAnimationSpecs : mStartSpec = " + mStartSpec + ", endSpec = " + + mEndSpec); + } + } + + /** + * Wraps {@link WindowMagnificationController#setScale(float)}. If the animation is + * running, it has no effect. + */ + void setScale(float scale) { + if (mValueAnimator.isRunning()) { + return; + } + mController.setScale(scale); + } + + /** + * Wraps {@link WindowMagnificationController#deleteWindowMagnification()}} with transition + * animation. If the window magnification is enabling, it runs the animation in reverse. + */ + void deleteWindowMagnification() { + if (mState == STATE_DISABLED || mState == STATE_DISABLING) { + return; + } + mStartSpec.set(/* scale*/ 1.0f, Float.NaN, Float.NaN); + mEndSpec.set(/* scale*/ mController.getScale(), Float.NaN, Float.NaN); + + mValueAnimator.reverse(); + setState(STATE_DISABLING); + } + + /** + * Wraps {@link WindowMagnificationController#moveWindowMagnifier(float, float)}. If the + * animation is running, it has no effect. + * @param offsetX the amount in pixels to offset the window magnifier in the X direction, in + * current screen pixels. + * @param offsetY the amount in pixels to offset the window magnifier in the Y direction, in + * current screen pixels. + */ + void moveWindowMagnifier(float offsetX, float offsetY) { + if (mValueAnimator.isRunning()) { + return; + } + mController.moveWindowMagnifier(offsetX, offsetY); + } + + void onConfigurationChanged(int configDiff) { + mController.onConfigurationChanged(configDiff); + } + + private void setState(@MagnificationState int state) { + if (DEBUG) { + Log.d(TAG, "setState from " + mState + " to " + state); + } + mState = state; + } + + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + if (mState == STATE_DISABLING) { + mController.deleteWindowMagnification(); + setState(STATE_DISABLED); + } else if (mState == STATE_ENABLING) { + setState(STATE_ENABLED); + } else { + Log.w(TAG, "onAnimationEnd unexpected state:" + mState); + } + } + + @Override + public void onAnimationCancel(Animator animation) { + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + final float fract = animation.getAnimatedFraction(); + final float sentScale = mStartSpec.mScale + (mEndSpec.mScale - mStartSpec.mScale) * fract; + final float centerX = + mStartSpec.mCenterX + (mEndSpec.mCenterX - mStartSpec.mCenterX) * fract; + final float centerY = + mStartSpec.mCenterY + (mEndSpec.mCenterY - mStartSpec.mCenterY) * fract; + mController.enableWindowMagnification(sentScale, centerX, centerY); + } + + private static ValueAnimator newValueAnimator(Resources resources) { + final ValueAnimator valueAnimator = new ValueAnimator(); + valueAnimator.setDuration( + resources.getInteger(com.android.internal.R.integer.config_longAnimTime)); + valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f)); + valueAnimator.setFloatValues(0.0f, 1.0f); + return valueAnimator; + } + + private static class AnimationSpec { + private float mScale = Float.NaN; + private float mCenterX = Float.NaN; + private float mCenterY = Float.NaN; + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (other == null || getClass() != other.getClass()) { + return false; + } + + final AnimationSpec s = (AnimationSpec) other; + return mScale == s.mScale && mCenterX == s.mCenterX && mCenterY == s.mCenterY; + } + + @Override + public int hashCode() { + int result = (mScale != +0.0f ? Float.floatToIntBits(mScale) : 0); + result = 31 * result + (mCenterX != +0.0f ? Float.floatToIntBits(mCenterX) : 0); + result = 31 * result + (mCenterY != +0.0f ? Float.floatToIntBits(mCenterY) : 0); + return result; + } + + void set(float scale, float centerX, float centerY) { + mScale = scale; + mCenterX = centerX; + mCenterY = centerY; + } + + @Override + public String toString() { + return "AnimationSpec{" + + "mScale=" + mScale + + ", mCenterX=" + mCenterX + + ", mCenterY=" + mCenterY + + '}'; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index 798b751c03ee..494a0f64cea4 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -150,7 +150,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mMirrorViewGeometryVsyncCallback = l -> { - if (mMirrorView != null && mMirrorSurface != null) { + if (isWindowVisible() && mMirrorSurface != null) { calculateSourceBounds(mMagnificationFrame, mScale); // The final destination for the magnification surface should be at 0,0 // since the ViewRootImpl's position will change @@ -203,13 +203,13 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold * @param configDiff a bit mask of the differences between the configurations */ void onConfigurationChanged(int configDiff) { + if (!isWindowVisible()) { + return; + } if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) { updateDimensions(); - // TODO(b/145780606): update toggle button UI. - if (mMirrorView != null) { - mWm.removeView(mMirrorView); - createMirrorWindow(); - } + mWm.removeView(mMirrorView); + createMirrorWindow(); } else if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) { onRotate(); } @@ -502,7 +502,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold /** * Enables window magnification with specified parameters. * - * @param scale the target scale + * @param scale the target scale, or {@link Float#NaN} to leave unchanged * @param centerX the screen-relative X coordinate around which to center, * or {@link Float#NaN} to leave unchanged. * @param centerY the screen-relative Y coordinate around which to center, @@ -513,10 +513,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold : centerX - mMagnificationFrame.exactCenterX(); final float offsetY = Float.isNaN(centerY) ? 0 : centerY - mMagnificationFrame.exactCenterY(); - mScale = scale; + mScale = Float.isNaN(scale) ? mScale : scale; setMagnificationFrameBoundary(); updateMagnificationFramePosition((int) offsetX, (int) offsetY); - if (mMirrorView == null) { + if (!isWindowVisible()) { createMirrorWindow(); showControls(); } else { @@ -527,10 +527,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold /** * Sets the scale of the magnified region if it's visible. * - * @param scale the target scale + * @param scale the target scale, or {@link Float#NaN} to leave unchanged */ void setScale(float scale) { - if (mMirrorView == null || mScale == scale) { + if (!isWindowVisible() || mScale == scale) { return; } enableWindowMagnification(scale, Float.NaN, Float.NaN); @@ -552,4 +552,35 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold modifyWindowMagnification(mTransaction); } } + + /** + * Gets the scale. + * @return {@link Float#NaN} if the window is invisible. + */ + float getScale() { + return isWindowVisible() ? mScale : Float.NaN; + } + + /** + * Returns the screen-relative X coordinate of the center of the magnified bounds. + * + * @return the X coordinate. {@link Float#NaN} if the window is invisible. + */ + float getCenterX() { + return isWindowVisible() ? mMagnificationFrame.exactCenterX() : Float.NaN; + } + + /** + * Returns the screen-relative Y coordinate of the center of the magnified bounds. + * + * @return the Y coordinate. {@link Float#NaN} if the window is invisible. + */ + float getCenterY() { + return isWindowVisible() ? mMagnificationFrame.exactCenterY() : Float.NaN; + } + + //The window is visible when it is existed. + private boolean isWindowVisible() { + return mMirrorView != null; + } } diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java index 7e5b42653210..93a8df41c673 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java @@ -25,7 +25,9 @@ public class AppOpItem { private int mUid; private String mPackageName; private long mTimeStarted; - private String mState; + private StringBuilder mState; + // This is only used for items with mCode == AppOpsManager.OP_RECORD_AUDIO + private boolean mSilenced; public AppOpItem(int code, int uid, String packageName, long timeStarted) { this.mCode = code; @@ -36,9 +38,8 @@ public class AppOpItem { .append("AppOpItem(") .append("Op code=").append(code).append(", ") .append("UID=").append(uid).append(", ") - .append("Package name=").append(packageName) - .append(")") - .toString(); + .append("Package name=").append(packageName).append(", ") + .append("Paused="); } public int getCode() { @@ -57,8 +58,16 @@ public class AppOpItem { return mTimeStarted; } + public void setSilenced(boolean silenced) { + mSilenced = silenced; + } + + public boolean isSilenced() { + return mSilenced; + } + @Override public String toString() { - return mState; + return mState.append(mSilenced).append(")").toString(); } } diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java index 6512624f5064..8187a2235c0a 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java @@ -19,6 +19,8 @@ package com.android.systemui.appops; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; +import android.media.AudioManager; +import android.media.AudioRecordingConfiguration; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; @@ -63,6 +65,7 @@ public class AppOpsControllerImpl implements AppOpsController, private static final boolean DEBUG = false; private final AppOpsManager mAppOps; + private final AudioManager mAudioManager; private H mBGHandler; private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>(); private final SparseArray<Set<Callback>> mCallbacksByCode = new SparseArray<>(); @@ -73,6 +76,9 @@ public class AppOpsControllerImpl implements AppOpsController, private final List<AppOpItem> mActiveItems = new ArrayList<>(); @GuardedBy("mNotedItems") private final List<AppOpItem> mNotedItems = new ArrayList<>(); + @GuardedBy("mActiveItems") + private final SparseArray<ArrayList<AudioRecordingConfiguration>> mRecordingsByUid = + new SparseArray<>(); protected static final int[] OPS = new int[] { AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, @@ -88,7 +94,8 @@ public class AppOpsControllerImpl implements AppOpsController, Context context, @Background Looper bgLooper, DumpManager dumpManager, - PermissionFlagsCache cache + PermissionFlagsCache cache, + AudioManager audioManager ) { mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mFlagsCache = cache; @@ -97,6 +104,7 @@ public class AppOpsControllerImpl implements AppOpsController, for (int i = 0; i < numOps; i++) { mCallbacksByCode.put(OPS[i], new ArraySet<>()); } + mAudioManager = audioManager; dumpManager.registerDumpable(TAG, this); } @@ -111,12 +119,19 @@ public class AppOpsControllerImpl implements AppOpsController, if (listening) { mAppOps.startWatchingActive(OPS, this); mAppOps.startWatchingNoted(OPS, this); + mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler); + mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged( + mAudioManager.getActiveRecordingConfigurations())); + } else { mAppOps.stopWatchingActive(this); mAppOps.stopWatchingNoted(this); + mAudioManager.unregisterAudioRecordingCallback(mAudioRecordingCallback); + mBGHandler.removeCallbacksAndMessages(null); // null removes all synchronized (mActiveItems) { mActiveItems.clear(); + mRecordingsByUid.clear(); } synchronized (mNotedItems) { mNotedItems.clear(); @@ -189,9 +204,12 @@ public class AppOpsControllerImpl implements AppOpsController, AppOpItem item = getAppOpItemLocked(mActiveItems, code, uid, packageName); if (item == null && active) { item = new AppOpItem(code, uid, packageName, System.currentTimeMillis()); + if (code == AppOpsManager.OP_RECORD_AUDIO) { + item.setSilenced(isAnyRecordingPausedLocked(uid)); + } mActiveItems.add(item); if (DEBUG) Log.w(TAG, "Added item: " + item.toString()); - return true; + return !item.isSilenced(); } else if (item != null && !active) { mActiveItems.remove(item); if (DEBUG) Log.w(TAG, "Removed item: " + item.toString()); @@ -215,7 +233,7 @@ public class AppOpsControllerImpl implements AppOpsController, active = getAppOpItemLocked(mActiveItems, code, uid, packageName) != null; } if (!active) { - notifySuscribers(code, uid, packageName, false); + notifySuscribersWorker(code, uid, packageName, false); } } @@ -324,7 +342,7 @@ public class AppOpsControllerImpl implements AppOpsController, AppOpItem item = mActiveItems.get(i); if ((userId == UserHandle.USER_ALL || UserHandle.getUserId(item.getUid()) == userId) - && isUserVisible(item)) { + && isUserVisible(item) && !item.isSilenced()) { list.add(item); } } @@ -343,6 +361,10 @@ public class AppOpsControllerImpl implements AppOpsController, return list; } + private void notifySuscribers(int code, int uid, String packageName, boolean active) { + mBGHandler.post(() -> notifySuscribersWorker(code, uid, packageName, active)); + } + @Override public void onOpActiveChanged(int code, int uid, String packageName, boolean active) { if (DEBUG) { @@ -360,7 +382,7 @@ public class AppOpsControllerImpl implements AppOpsController, // If active is false, we only send the update if the op is not actively noted (prevent // early removal) if (!alsoNoted) { - mBGHandler.post(() -> notifySuscribers(code, uid, packageName, active)); + notifySuscribers(code, uid, packageName, active); } } @@ -378,11 +400,11 @@ public class AppOpsControllerImpl implements AppOpsController, alsoActive = getAppOpItemLocked(mActiveItems, code, uid, packageName) != null; } if (!alsoActive) { - mBGHandler.post(() -> notifySuscribers(code, uid, packageName, true)); + notifySuscribers(code, uid, packageName, true); } } - private void notifySuscribers(int code, int uid, String packageName, boolean active) { + private void notifySuscribersWorker(int code, int uid, String packageName, boolean active) { if (mCallbacksByCode.contains(code) && isUserVisible(code, uid, packageName)) { if (DEBUG) Log.d(TAG, "Notifying of change in package " + packageName); for (Callback cb: mCallbacksByCode.get(code)) { @@ -408,6 +430,61 @@ public class AppOpsControllerImpl implements AppOpsController, } + private boolean isAnyRecordingPausedLocked(int uid) { + List<AudioRecordingConfiguration> configs = mRecordingsByUid.get(uid); + if (configs == null) return false; + int configsNum = configs.size(); + for (int i = 0; i < configsNum; i++) { + AudioRecordingConfiguration config = configs.get(i); + if (config.isClientSilenced()) return true; + } + return false; + } + + private void updateRecordingPausedStatus() { + synchronized (mActiveItems) { + int size = mActiveItems.size(); + for (int i = 0; i < size; i++) { + AppOpItem item = mActiveItems.get(i); + if (item.getCode() == AppOpsManager.OP_RECORD_AUDIO) { + boolean paused = isAnyRecordingPausedLocked(item.getUid()); + if (item.isSilenced() != paused) { + item.setSilenced(paused); + notifySuscribers( + item.getCode(), + item.getUid(), + item.getPackageName(), + !item.isSilenced() + ); + } + } + } + } + } + + private AudioManager.AudioRecordingCallback mAudioRecordingCallback = + new AudioManager.AudioRecordingCallback() { + @Override + public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) { + synchronized (mActiveItems) { + mRecordingsByUid.clear(); + final int recordingsCount = configs.size(); + for (int i = 0; i < recordingsCount; i++) { + AudioRecordingConfiguration recording = configs.get(i); + + ArrayList<AudioRecordingConfiguration> recordings = mRecordingsByUid.get( + recording.getClientUid()); + if (recordings == null) { + recordings = new ArrayList<>(); + mRecordingsByUid.put(recording.getClientUid(), recordings); + } + recordings.add(recording); + } + } + updateRecordingPausedStatus(); + } + }; + protected class H extends Handler { H(Looper looper) { super(looper); diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistantSessionEvent.kt b/packages/SystemUI/src/com/android/systemui/assist/AssistantSessionEvent.kt index 8b953fa46441..be089b12a95d 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistantSessionEvent.kt +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistantSessionEvent.kt @@ -21,7 +21,7 @@ import com.android.internal.logging.UiEventLogger enum class AssistantSessionEvent(private val id: Int) : UiEventLogger.UiEventEnum { @UiEvent(doc = "Unknown assistant session event") - ASSISTANT_SESSION_UNKNOWN(523), + ASSISTANT_SESSION_UNKNOWN(0), @UiEvent(doc = "Assistant session dismissed due to timeout") ASSISTANT_SESSION_TIMEOUT_DISMISS(524), diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index c5639ea6fcde..9c5f9fe8bcc0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -139,7 +139,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED, DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE, DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT, - DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED}) + DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED, + DISMISS_NO_BUBBLE_UP}) @Target({FIELD, LOCAL_VARIABLE, PARAMETER}) @interface DismissReason {} @@ -156,6 +157,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi static final int DISMISS_OVERFLOW_MAX_REACHED = 11; static final int DISMISS_SHORTCUT_REMOVED = 12; static final int DISMISS_PACKAGE_REMOVED = 13; + static final int DISMISS_NO_BUBBLE_UP = 14; private final Context mContext; private final NotificationEntryManager mNotificationEntryManager; @@ -1262,8 +1264,18 @@ public class BubbleController implements ConfigurationController.ConfigurationLi rankingMap.getRanking(key, mTmpRanking); boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key); if (isActiveBubble && !mTmpRanking.canBubble()) { - mBubbleData.dismissBubbleWithKey(entry.getKey(), - BubbleController.DISMISS_BLOCKED); + // If this entry is no longer allowed to bubble, dismiss with the BLOCKED reason. + // This means that the app or channel's ability to bubble has been revoked. + mBubbleData.dismissBubbleWithKey( + key, BubbleController.DISMISS_BLOCKED); + } else if (isActiveBubble + && !mNotificationInterruptStateProvider.shouldBubbleUp(entry)) { + // If this entry is allowed to bubble, but cannot currently bubble up, dismiss it. + // This happens when DND is enabled and configured to hide bubbles. Dismissing with + // the reason DISMISS_NO_BUBBLE_UP will retain the underlying notification, so that + // the bubble will be re-created if shouldBubbleUp returns true. + mBubbleData.dismissBubbleWithKey( + key, BubbleController.DISMISS_NO_BUBBLE_UP); } else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) { entry.setFlagBubble(true); onEntryUpdated(entry); @@ -1340,8 +1352,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mStackView.removeBubble(bubble); } - // If the bubble is removed for user switching, leave the notification in place. - if (reason == DISMISS_USER_CHANGED) { + // Leave the notification in place if we're dismissing due to user switching, or + // because DND is suppressing the bubble. In both of those cases, we need to be able + // to restore the bubble from the notification later. + if (reason == DISMISS_USER_CHANGED || reason == DISMISS_NO_BUBBLE_UP) { continue; } if (reason == DISMISS_NOTIF_CANCEL) { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java index 9fdbb6daca51..9c55095e85e5 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java @@ -16,9 +16,6 @@ package com.android.systemui.dagger; -import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; - -import android.content.ContentProvider; import android.content.Context; import com.android.systemui.BootCompleteCacheImpl; @@ -26,14 +23,12 @@ import com.android.systemui.Dependency; import com.android.systemui.InitController; import com.android.systemui.SystemUIAppComponentFactory; import com.android.systemui.dump.DumpManager; -import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.KeyguardSliceProvider; import com.android.systemui.onehanded.dagger.OneHandedModule; import com.android.systemui.pip.phone.dagger.PipModule; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.InjectionInflationController; -import javax.inject.Named; import javax.inject.Singleton; import dagger.BindsInstance; @@ -42,6 +37,7 @@ import dagger.Component; /** * Root component for Dagger injection. */ +// TODO(b/162923491): Move most of these modules to SysUIComponent. @Singleton @Component(modules = { DefaultComponentBinder.class, @@ -52,21 +48,32 @@ import dagger.Component; SystemServicesModule.class, SystemUIBinder.class, SystemUIModule.class, - SystemUIDefaultModule.class}) -public interface SystemUIRootComponent { + SystemUIDefaultModule.class, + WMModule.class}) +public interface GlobalRootComponent { /** - * Builder for a SystemUIRootComponent. + * Builder for a GlobalRootComponent. */ @Component.Builder interface Builder { @BindsInstance Builder context(Context context); - SystemUIRootComponent build(); + GlobalRootComponent build(); } /** + * Builder for a WMComponent. + */ + WMComponent.Builder getWMComponentBuilder(); + + /** + * Builder for a SysuiComponent. + */ + SysUIComponent.Builder getSysUIComponent(); + + /** * Provides a BootCompleteCache. */ @Singleton @@ -95,28 +102,15 @@ public interface SystemUIRootComponent { DumpManager createDumpManager(); /** - * FragmentCreator generates all Fragments that need injection. - */ - @Singleton - FragmentService.FragmentCreator createFragmentCreator(); - - - /** * Creates a InitController. */ @Singleton InitController getInitController(); /** - * ViewCreator generates all Views that need injection. - */ - InjectionInflationController.ViewCreator createViewCreator(); - - /** - * Whether notification long press is allowed. + * ViewInstanceCreator generates all Views that need injection. */ - @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) - boolean allowNotificationLongPressName(); + InjectionInflationController.ViewInstanceCreator.Factory createViewInstanceCreatorFactory(); /** * Member injection into the supplied argument. @@ -126,10 +120,5 @@ public interface SystemUIRootComponent { /** * Member injection into the supplied argument. */ - void inject(ContentProvider contentProvider); - - /** - * Member injection into the supplied argument. - */ void inject(KeyguardSliceProvider keyguardSliceProvider); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java new file mode 100644 index 000000000000..9b527bfeda27 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dagger; + +import dagger.Subcomponent; + +/** + * Dagger Subcomponent for Core SysUI. + */ +@SysUISingleton +@Subcomponent(modules = {}) +public interface SysUIComponent { + + /** + * Builder for a SysUIComponent. + */ + @Subcomponent.Builder + interface Builder { + SysUIComponent build(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java new file mode 100644 index 000000000000..a4b33427cbda --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +/** + * Scope annotation for singleton items within the SysUIComponent. + */ +@Documented +@Retention(RUNTIME) +@Scope +public @interface SysUISingleton { +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java index 803e56db8ff3..4fd31c7609e2 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java @@ -72,7 +72,14 @@ import dagger.Provides; * A dagger module for injecting default implementations of components of System UI that may be * overridden by the System UI implementation. */ -@Module(includes = {DividerModule.class, QSModule.class, WindowManagerShellModule.class}) +@Module(includes = { + DividerModule.class, + QSModule.class, + WindowManagerShellModule.class + }, + subcomponents = { + SysUIComponent.class + }) public abstract class SystemUIDefaultModule { @Singleton diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index fce545b421d5..f6db6d59bb6d 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -26,6 +26,7 @@ import com.android.systemui.BootCompleteCacheImpl; import com.android.systemui.assist.AssistModule; import com.android.systemui.doze.dagger.DozeComponent; import com.android.systemui.dump.DumpManager; +import com.android.systemui.fragments.FragmentService; import com.android.systemui.log.dagger.LogModule; import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -38,6 +39,7 @@ import com.android.systemui.statusbar.notification.collection.inflation.Notifica import com.android.systemui.statusbar.notification.people.PeopleHubModule; import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; +import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.phone.KeyguardLiftController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; @@ -72,7 +74,9 @@ import dagger.Provides; subcomponents = {StatusBarComponent.class, NotificationRowComponent.class, DozeComponent.class, - ExpandableNotificationRowComponent.class}) + ExpandableNotificationRowComponent.class, + NotificationShelfComponent.class, + FragmentService.FragmentCreator.class}) public abstract class SystemUIModule { @Binds diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java new file mode 100644 index 000000000000..929b61a3421c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dagger; + +import dagger.Subcomponent; + +/** + * Dagger Subcomponent for WindowManager. + */ +@WMSingleton +@Subcomponent(modules = {}) +public interface WMComponent { + + /** + * Builder for a WMComponent. + */ + @Subcomponent.Builder + interface Builder { + WMComponent build(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMModule.java b/packages/SystemUI/src/com/android/systemui/dagger/WMModule.java new file mode 100644 index 000000000000..2894780e04b8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMModule.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dagger; + +import dagger.Module; + +/** + * Dagger module for including the WMComponent. + */ +@Module(subcomponents = {WMComponent.class}) +public abstract class WMModule { +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java b/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java new file mode 100644 index 000000000000..7292b9e459e0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +/** + * Scope annotation for singleton items within the WMComponent. + */ +@Documented +@Retention(RUNTIME) +@Scope +public @interface WMSingleton { +} diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java index ae200763b3b0..0507592a89e1 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java @@ -21,7 +21,6 @@ import android.util.ArrayMap; import android.view.View; import com.android.systemui.Dumpable; -import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.qs.QSFragment; import com.android.systemui.statusbar.phone.NavigationBarFragment; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -61,9 +60,9 @@ public class FragmentService implements Dumpable { }; @Inject - public FragmentService(SystemUIRootComponent rootComponent, + public FragmentService(FragmentCreator.Factory fragmentCreatorFactory, ConfigurationController configurationController) { - mFragmentCreator = rootComponent.createFragmentCreator(); + mFragmentCreator = fragmentCreatorFactory.build(); initInjectionMap(); configurationController.addCallback(mConfigurationListener); } @@ -121,6 +120,11 @@ public class FragmentService implements Dumpable { */ @Subcomponent public interface FragmentCreator { + /** Factory for creating a FragmentCreator. */ + @Subcomponent.Factory + interface Factory { + FragmentCreator build(); + } /** * Inject a NavigationBarFragment. */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index 3a37c0fd4634..daef2c506ad3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -52,7 +52,6 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SystemUIAppComponentFactory; -import com.android.systemui.SystemUIFactory; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.StatusBarState; @@ -72,6 +71,9 @@ import javax.inject.Inject; /** * Simple Slice provider that shows the current date. + * + * Injection is handled by {@link SystemUIAppComponentFactory} + + * {@link com.android.systemui.dagger.GlobalRootComponent#inject(KeyguardSliceProvider)}. */ public class KeyguardSliceProvider extends SliceProvider implements NextAlarmController.NextAlarmChangeCallback, ZenModeController.Callback, @@ -298,7 +300,8 @@ public class KeyguardSliceProvider extends SliceProvider implements @Override public boolean onCreateSliceProvider() { mContextAvailableCallback.onContextAvailable(getContext()); - inject(); + mMediaWakeLock = new SettableWakeLock(WakeLock.createPartial(getContext(), "media"), + "media"); synchronized (KeyguardSliceProvider.sInstanceLock) { KeyguardSliceProvider oldInstance = KeyguardSliceProvider.sInstance; if (oldInstance != null) { @@ -319,13 +322,6 @@ public class KeyguardSliceProvider extends SliceProvider implements } @VisibleForTesting - protected void inject() { - SystemUIFactory.getInstance().getRootComponent().inject(this); - mMediaWakeLock = new SettableWakeLock(WakeLock.createPartial(getContext(), "media"), - "media"); - } - - @VisibleForTesting protected void onDestroy() { synchronized (KeyguardSliceProvider.sInstanceLock) { mNextAlarmController.removeCallback(this); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 75f4809d752f..d55ac7c7fc4b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -85,7 +85,6 @@ import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.SystemUI; -import com.android.systemui.SystemUIFactory; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.dump.DumpManager; @@ -229,6 +228,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { /** TrustManager for letting it know when we change visibility */ private final TrustManager mTrustManager; + private final InjectionInflationController mInjectionInflationController; /** * Used to keep the device awake while to ensure the keyguard finishes opening before @@ -723,7 +723,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { @UiBackground Executor uiBgExecutor, PowerManager powerManager, TrustManager trustManager, DeviceConfigProxy deviceConfig, - NavigationModeController navigationModeController) { + NavigationModeController navigationModeController, + InjectionInflationController injectionInflationController) { super(context); mFalsingManager = falsingManager; mLockPatternUtils = lockPatternUtils; @@ -734,6 +735,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { mUpdateMonitor = keyguardUpdateMonitor; mPM = powerManager; mTrustManager = trustManager; + mInjectionInflationController = injectionInflationController; dumpManager.registerDumpable(getClass().getName(), this); mDeviceConfig = deviceConfig; mShowHomeOverLockscreen = mDeviceConfig.getBoolean( @@ -773,10 +775,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter, SYSTEMUI_PERMISSION, null /* scheduler */); - InjectionInflationController injectionInflationController = - new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()); mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, - injectionInflationController); + mInjectionInflationController); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 83c95b77b716..ab41afb5a831 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -32,6 +32,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.phone.NavigationModeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.DeviceConfigProxy; +import com.android.systemui.util.InjectionInflationController; import java.util.concurrent.Executor; @@ -64,7 +65,8 @@ public class KeyguardModule { TrustManager trustManager, @UiBackground Executor uiBgExecutor, DeviceConfigProxy deviceConfig, - NavigationModeController navigationModeController) { + NavigationModeController navigationModeController, + InjectionInflationController injectionInflationController) { return new KeyguardViewMediator( context, falsingManager, @@ -78,6 +80,7 @@ public class KeyguardModule { powerManager, trustManager, deviceConfig, - navigationModeController); + navigationModeController, + injectionInflationController); } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index 7f610d1a8467..b993faabe9b1 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -10,6 +10,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.LinearLayout +import androidx.annotation.VisibleForTesting import com.android.systemui.R import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter @@ -21,6 +22,7 @@ import com.android.systemui.util.Utils import com.android.systemui.util.animation.UniqueObjectHostView import com.android.systemui.util.animation.requiresRemeasuring import com.android.systemui.util.concurrency.DelayableExecutor +import java.util.TreeMap import javax.inject.Inject import javax.inject.Provider import javax.inject.Singleton @@ -102,9 +104,7 @@ class MediaCarouselController @Inject constructor( private val mediaCarousel: MediaScrollView private val mediaCarouselScrollHandler: MediaCarouselScrollHandler val mediaFrame: ViewGroup - val mediaPlayers: MutableMap<String, MediaControlPanel> = mutableMapOf() private lateinit var settingsButton: View - private val mediaData: MutableMap<String, MediaData> = mutableMapOf() private val mediaContent: ViewGroup private val pageIndicator: PageIndicator private val visualStabilityCallback: VisualStabilityManager.Callback @@ -122,7 +122,7 @@ class MediaCarouselController @Inject constructor( set(value) { if (field != value) { field = value - for (player in mediaPlayers.values) { + for (player in MediaPlayerData.players()) { player.setListening(field) } } @@ -167,20 +167,18 @@ class MediaCarouselController @Inject constructor( true /* persistent */) mediaManager.addListener(object : MediaDataManager.Listener { override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) { - oldKey?.let { mediaData.remove(it) } if (!data.active && !Utils.useMediaResumption(context)) { // This view is inactive, let's remove this! This happens e.g when dismissing / // timing out a view. We still have the data around because resumption could // be on, but we should save the resources and release this. + oldKey?.let { MediaPlayerData.removeMediaPlayer(it) } onMediaDataRemoved(key) } else { - mediaData.put(key, data) addOrUpdatePlayer(key, oldKey, data) } } override fun onMediaDataRemoved(key: String) { - mediaData.remove(key) removePlayer(key) } }) @@ -223,53 +221,36 @@ class MediaCarouselController @Inject constructor( } private fun reorderAllPlayers() { - for (mediaPlayer in mediaPlayers.values) { - val view = mediaPlayer.view?.player - if (mediaPlayer.isPlaying && mediaContent.indexOfChild(view) != 0) { - mediaContent.removeView(view) - mediaContent.addView(view, 0) + mediaContent.removeAllViews() + for (mediaPlayer in MediaPlayerData.players()) { + mediaPlayer.view?.let { + mediaContent.addView(it.player) } } mediaCarouselScrollHandler.onPlayersChanged() } private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData) { - // If the key was changed, update entry - val oldData = mediaPlayers[oldKey] - if (oldData != null) { - val oldData = mediaPlayers.remove(oldKey) - mediaPlayers.put(key, oldData!!)?.let { - Log.wtf(TAG, "new key $key already exists when migrating from $oldKey") - } - } - var existingPlayer = mediaPlayers[key] + val existingPlayer = MediaPlayerData.getMediaPlayer(key, oldKey) if (existingPlayer == null) { - existingPlayer = mediaControlPanelFactory.get() - existingPlayer.attach(PlayerViewHolder.create(LayoutInflater.from(context), - mediaContent)) - existingPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions - mediaPlayers[key] = existingPlayer + var newPlayer = mediaControlPanelFactory.get() + newPlayer.attach(PlayerViewHolder.create(LayoutInflater.from(context), mediaContent)) + newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions + MediaPlayerData.addMediaPlayer(key, data, newPlayer) val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - existingPlayer.view?.player?.setLayoutParams(lp) - existingPlayer.bind(data) - existingPlayer.setListening(currentlyExpanded) - updatePlayerToState(existingPlayer, noAnimation = true) - if (existingPlayer.isPlaying) { - mediaContent.addView(existingPlayer.view?.player, 0) - } else { - mediaContent.addView(existingPlayer.view?.player) - } + newPlayer.view?.player?.setLayoutParams(lp) + newPlayer.bind(data) + newPlayer.setListening(currentlyExpanded) + updatePlayerToState(newPlayer, noAnimation = true) + reorderAllPlayers() } else { existingPlayer.bind(data) - if (existingPlayer.isPlaying && - mediaContent.indexOfChild(existingPlayer.view?.player) != 0) { - if (visualStabilityManager.isReorderingAllowed) { - mediaContent.removeView(existingPlayer.view?.player) - mediaContent.addView(existingPlayer.view?.player, 0) - } else { - needsReordering = true - } + MediaPlayerData.addMediaPlayer(key, data, existingPlayer) + if (visualStabilityManager.isReorderingAllowed) { + reorderAllPlayers() + } else { + needsReordering = true } } updatePageIndicator() @@ -277,13 +258,13 @@ class MediaCarouselController @Inject constructor( mediaCarousel.requiresRemeasuring = true // Check postcondition: mediaContent should have the same number of children as there are // elements in mediaPlayers. - if (mediaPlayers.size != mediaContent.childCount) { + if (MediaPlayerData.players().size != mediaContent.childCount) { Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync") } } private fun removePlayer(key: String) { - val removed = mediaPlayers.remove(key) + val removed = MediaPlayerData.removeMediaPlayer(key) removed?.apply { mediaCarouselScrollHandler.onPrePlayerRemoved(removed) mediaContent.removeView(removed.view?.player) @@ -294,12 +275,7 @@ class MediaCarouselController @Inject constructor( } private fun recreatePlayers() { - // Note that this will scramble the order of players. Actively playing sessions will, at - // least, still be put in the front. If we want to maintain order, then more work is - // needed. - mediaData.forEach { - key, data -> - removePlayer(key) + MediaPlayerData.mediaData().forEach { (key, data) -> addOrUpdatePlayer(key = key, oldKey = null, data = data) } } @@ -337,7 +313,7 @@ class MediaCarouselController @Inject constructor( currentStartLocation = startLocation currentEndLocation = endLocation currentTransitionProgress = progress - for (mediaPlayer in mediaPlayers.values) { + for (mediaPlayer in MediaPlayerData.players()) { updatePlayerToState(mediaPlayer, immediately) } maybeResetSettingsCog() @@ -386,7 +362,7 @@ class MediaCarouselController @Inject constructor( private fun updateCarouselDimensions() { var width = 0 var height = 0 - for (mediaPlayer in mediaPlayers.values) { + for (mediaPlayer in MediaPlayerData.players()) { val controller = mediaPlayer.mediaViewController // When transitioning the view to gone, the view gets smaller, but the translation // Doesn't, let's add the translation @@ -448,7 +424,7 @@ class MediaCarouselController @Inject constructor( this.desiredLocation = desiredLocation this.desiredHostState = it currentlyExpanded = it.expansion > 0 - for (mediaPlayer in mediaPlayers.values) { + for (mediaPlayer in MediaPlayerData.players()) { if (animate) { mediaPlayer.mediaViewController.animatePendingStateChange( duration = duration, @@ -470,7 +446,7 @@ class MediaCarouselController @Inject constructor( } fun closeGuts() { - mediaPlayers.values.forEach { + MediaPlayerData.players().forEach { it.closeGuts(true) } } @@ -497,3 +473,50 @@ class MediaCarouselController @Inject constructor( } } } + +@VisibleForTesting +internal object MediaPlayerData { + private data class MediaSortKey( + val data: MediaData, + val updateTime: Long = 0, + val isPlaying: Boolean = false + ) + + private val comparator = + compareByDescending<MediaSortKey> { it.isPlaying } + .thenByDescending { it.data.isLocalSession } + .thenByDescending { !it.data.resumption } + .thenByDescending { it.updateTime } + + private val mediaPlayers = TreeMap<MediaSortKey, MediaControlPanel>(comparator) + private val mediaData: MutableMap<String, MediaSortKey> = mutableMapOf() + + fun addMediaPlayer(key: String, data: MediaData, player: MediaControlPanel) { + removeMediaPlayer(key) + val sortKey = MediaSortKey(data, System.currentTimeMillis(), player.isPlaying()) + mediaData.put(key, sortKey) + mediaPlayers.put(sortKey, player) + } + + fun getMediaPlayer(key: String, oldKey: String?): MediaControlPanel? { + // If the key was changed, update entry + oldKey?.let { + if (it != key) { + mediaData.remove(it)?.let { sortKey -> mediaData.put(key, sortKey) } + } + } + return mediaData.get(key)?.let { mediaPlayers.get(it) } + } + + fun removeMediaPlayer(key: String) = mediaData.remove(key)?.let { mediaPlayers.remove(it) } + + fun mediaData() = mediaData.entries.map { e -> Pair(e.key, e.value.data) } + + fun players() = mediaPlayers.values + + @VisibleForTesting + fun clear() { + mediaData.clear() + mediaPlayers.clear() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt index dafc52ad8025..d6a02687c905 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt @@ -82,6 +82,10 @@ data class MediaData( */ var resumeAction: Runnable?, /** + * Local or remote playback + */ + var isLocalSession: Boolean = true, + /** * Indicates that this player is a resumption player (ie. It only shows a play actions which * will start the app and start playing). */ diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 8a51c8515852..30e10f655026 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -31,6 +31,7 @@ import android.graphics.drawable.Drawable import android.graphics.drawable.Icon import android.media.MediaDescription import android.media.MediaMetadata +import android.media.session.MediaController import android.media.session.MediaSession import android.net.Uri import android.os.UserHandle @@ -44,6 +45,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.notification.MediaNotificationProcessor import com.android.systemui.statusbar.notification.row.HybridGroupManager import com.android.systemui.util.Assert @@ -97,6 +99,7 @@ class MediaDataManager( dumpManager: DumpManager, mediaTimeoutListener: MediaTimeoutListener, mediaResumeListener: MediaResumeListener, + private val activityStarter: ActivityStarter, private var useMediaResumption: Boolean, private val useQsMediaPlayer: Boolean ) : Dumpable { @@ -113,10 +116,11 @@ class MediaDataManager( dumpManager: DumpManager, broadcastDispatcher: BroadcastDispatcher, mediaTimeoutListener: MediaTimeoutListener, - mediaResumeListener: MediaResumeListener + mediaResumeListener: MediaResumeListener, + activityStarter: ActivityStarter ) : this(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory, broadcastDispatcher, dumpManager, mediaTimeoutListener, mediaResumeListener, - Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context)) + activityStarter, Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context)) private val appChangeReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { @@ -328,7 +332,8 @@ class MediaDataManager( ) { val token = sbn.notification.extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) as MediaSession.Token? - val metadata = mediaControllerFactory.create(token).metadata + val mediaController = mediaControllerFactory.create(token) + val metadata = mediaController.metadata // Foreground and Background colors computed from album art val notif: Notification = sbn.notification @@ -403,10 +408,13 @@ class MediaDataManager( } val runnable = if (action.actionIntent != null) { Runnable { - try { - action.actionIntent.send() - } catch (e: PendingIntent.CanceledException) { - Log.d(TAG, "Intent canceled", e) + if (action.isAuthenticationRequired()) { + activityStarter.dismissKeyguardThenExecute ({ + var result = sendPendingIntent(action.actionIntent) + result + }, {}, true) + } else { + sendPendingIntent(action.actionIntent) } } } else { @@ -420,6 +428,9 @@ class MediaDataManager( } } + val isLocalSession = mediaController.playbackInfo?.playbackType == + MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL ?: true + foregroundExecutor.execute { val resumeAction: Runnable? = mediaEntries[key]?.resumeAction val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true @@ -427,8 +438,8 @@ class MediaDataManager( onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, bgColor, app, smallIconDrawable, artist, song, artWorkIcon, actionIcons, actionsToShowCollapsed, sbn.packageName, token, notif.contentIntent, null, - active, resumeAction = resumeAction, notificationKey = key, - hasCheckedForResume = hasCheckedForResume)) + active, resumeAction = resumeAction, isLocalSession = isLocalSession, + notificationKey = key, hasCheckedForResume = hasCheckedForResume)) } } @@ -449,6 +460,15 @@ class MediaDataManager( return null } + private fun sendPendingIntent(intent: PendingIntent): Boolean { + return try { + intent.send() + true + } catch (e: PendingIntent.CanceledException) { + Log.d(TAG, "Intent canceled", e) + false + } + } /** * Load a bitmap from a URI * @param uri the uri to load diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java index 8550959aa2c4..2e91697de849 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java @@ -26,6 +26,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; import android.os.Looper; +import android.os.SystemProperties; import android.util.Log; import android.view.SurfaceControl; import android.window.DisplayAreaInfo; @@ -61,6 +62,8 @@ import javax.inject.Inject; */ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implements Dumpable { private static final String TAG = "OneHandedDisplayAreaOrganizer"; + private static final String ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION = + "persist.debug.one_handed_translate_animation_duration"; @VisibleForTesting static final int MSG_RESET_IMMEDIATE = 1; @@ -156,8 +159,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen mDisplayController = displayController; mDefaultDisplayBounds.set(getDisplayBounds()); mLastVisualDisplayBounds.set(getDisplayBounds()); - mEnterExitAnimationDurationMs = context.getResources().getInteger( - com.android.systemui.R.integer.config_one_handed_translate_animation_duration); + mEnterExitAnimationDurationMs = + SystemProperties.getInt(ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION, 300); mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; mTutorialHandler = tutorialHandler; } diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java index a3921ee54fec..42524bb33818 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java @@ -24,13 +24,13 @@ import android.content.ComponentName; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; +import android.os.SystemProperties; import android.view.KeyEvent; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dumpable; -import com.android.systemui.R; import com.android.systemui.model.SysUiState; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; @@ -50,6 +50,8 @@ import javax.inject.Singleton; @Singleton public class OneHandedManagerImpl implements OneHandedManager, Dumpable { private static final String TAG = "OneHandedManager"; + private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = + "persist.debug.one_handed_offset_percentage"; private boolean mIsOneHandedEnabled; private boolean mIsSwipeToNotificationEnabled; @@ -117,8 +119,8 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { mDisplayController = displayController; mDisplayController.addDisplayChangingController(mRotationController); mSysUiFlagContainer = sysUiState; - mOffSetFraction = - context.getResources().getFraction(R.fraction.config_one_handed_offset, 1, 1); + mOffSetFraction = SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50) / 100.0f; + mIsOneHandedEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled( context.getContentResolver()); mIsSwipeToNotificationEnabled = OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java index b28730d004f6..de34b2ec831d 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java @@ -22,6 +22,7 @@ import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; +import android.os.SystemProperties; import android.provider.Settings; import android.view.Gravity; import android.view.LayoutInflater; @@ -50,6 +51,8 @@ import javax.inject.Singleton; @Singleton public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Dumpable { private static final String TAG = "OneHandedTutorialHandler"; + private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = + "persist.debug.one_handed_offset_percentage"; private static final int MAX_TUTORIAL_SHOW_COUNT = 2; private final Rect mLastUpdatedBounds = new Rect(); private final WindowManager mWindowManager; @@ -81,8 +84,8 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du mWindowManager = context.getSystemService(WindowManager.class); mTargetViewContainer = new FrameLayout(context); mTargetViewContainer.setClipChildren(false); - mTutorialAreaHeight = Math.round(mDisplaySize.y * context.getResources().getFraction( - R.fraction.config_one_handed_offset, 1, 1)); + mTutorialAreaHeight = Math.round(mDisplaySize.y + * (SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50) / 100.0f)); mTutorialView = LayoutInflater.from(context).inflate(R.xml.one_handed_tutorial, null); mTargetViewContainer.addView(mTutorialView); mCanShowTutorial = (Settings.Secure.getInt(mContentResolver, diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 01670285c0f4..f1c8b0cf0e42 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -186,20 +186,23 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio private class PipManagerPinnedStackListener extends PinnedStackListener { @Override public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { - if (mState == STATE_PIP) { - if (mImeVisible != imeVisible) { - if (imeVisible) { - // Save the IME height adjustment, and offset to not occlude the IME - mPipBounds.offset(0, -imeHeight); - mImeHeightAdjustment = imeHeight; - } else { - // Apply the inverse adjustment when the IME is hidden - mPipBounds.offset(0, mImeHeightAdjustment); + mHandler.post(() -> { + mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight); + if (mState == STATE_PIP) { + if (mImeVisible != imeVisible) { + if (imeVisible) { + // Save the IME height adjustment, and offset to not occlude the IME + mPipBounds.offset(0, -imeHeight); + mImeHeightAdjustment = imeHeight; + } else { + // Apply the inverse adjustment when the IME is hidden + mPipBounds.offset(0, mImeHeightAdjustment); + } + mImeVisible = imeVisible; + resizePinnedStack(STATE_PIP); } - mImeVisible = imeVisible; - resizePinnedStack(STATE_PIP); } - } + }); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java index f8655cc44d2a..52a2cecec6b1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java @@ -3,7 +3,9 @@ package com.android.systemui.qs; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; +import android.graphics.drawable.Animatable2; import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Log; import android.view.View; @@ -44,6 +46,24 @@ public class PageIndicator extends ViewGroup { private int mPosition = -1; private boolean mAnimating; + private final Animatable2.AnimationCallback mAnimationCallback = + new Animatable2.AnimationCallback() { + + @Override + public void onAnimationEnd(Drawable drawable) { + super.onAnimationEnd(drawable); + if (DEBUG) Log.d(TAG, "onAnimationEnd - queued: " + mQueuedPositions.size()); + if (drawable instanceof AnimatedVectorDrawable) { + ((AnimatedVectorDrawable) drawable).unregisterAnimationCallback( + mAnimationCallback); + } + mAnimating = false; + if (mQueuedPositions.size() != 0) { + setPosition(mQueuedPositions.remove(0)); + } + } + }; + public PageIndicator(Context context, AttributeSet attrs) { super(context, attrs); @@ -197,10 +217,8 @@ public class PageIndicator extends ViewGroup { final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) getContext().getDrawable(res); imageView.setImageDrawable(avd); avd.forceAnimationOnUI(); + avd.registerAnimationCallback(mAnimationCallback); avd.start(); - // TODO: Figure out how to user an AVD animation callback instead, which doesn't - // seem to be working right now... - postDelayed(mAnimationDone, ANIMATION_DURATION); } private int getTransition(boolean fromB, boolean isMajorAState, boolean isMajor) { @@ -264,15 +282,4 @@ public class PageIndicator extends ViewGroup { getChildAt(i).layout(left, 0, mPageIndicatorWidth + left, mPageIndicatorHeight); } } - - private final Runnable mAnimationDone = new Runnable() { - @Override - public void run() { - if (DEBUG) Log.d(TAG, "onAnimationEnd - queued: " + mQueuedPositions.size()); - mAnimating = false; - if (mQueuedPositions.size() != 0) { - setPosition(mQueuedPositions.remove(0)); - } - } - }; } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index c53523032353..6747281ac437 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -50,6 +50,7 @@ import android.graphics.drawable.LayerDrawable; import android.media.MediaActionSound; import android.net.Uri; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; @@ -556,11 +557,18 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset private void takeScreenshotInternal(Consumer<Uri> finisher, Rect crop) { // copy the input Rect, since SurfaceControl.screenshot can mutate it Rect screenRect = new Rect(crop); - int rot = mDisplay.getRotation(); int width = crop.width(); int height = crop.height(); - saveScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect, - Insets.NONE, true); + final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(displayToken) + .setSourceCrop(crop) + .setSize(width, height) + .build(); + final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = + SurfaceControl.captureDisplay(captureArgs); + final Bitmap screenshot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); + saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, true); } private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 6b023c07b1a6..95867957f648 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -161,7 +161,9 @@ public class NotificationRemoteInputManager implements Dumpable { ActivityManager.getService().resumeAppSwitches(); } catch (RemoteException e) { } - return mCallback.handleRemoteViewClick(view, pendingIntent, () -> { + Notification.Action action = getActionFromView(view, entry, pendingIntent); + return mCallback.handleRemoteViewClick(view, pendingIntent, + action == null ? false : action.isAuthenticationRequired(), () -> { Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view); options.second.setLaunchWindowingMode( WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); @@ -170,47 +172,56 @@ public class NotificationRemoteInputManager implements Dumpable { }); } - private void logActionClick( - View view, - NotificationEntry entry, - PendingIntent actionIntent) { + private @Nullable Notification.Action getActionFromView(View view, + NotificationEntry entry, PendingIntent actionIntent) { Integer actionIndex = (Integer) view.getTag(com.android.internal.R.id.notification_action_index_tag); if (actionIndex == null) { - // Custom action button, not logging. - return; + return null; } - ViewParent parent = view.getParent(); if (entry == null) { Log.w(TAG, "Couldn't determine notification for click."); - return; - } - StatusBarNotification statusBarNotification = entry.getSbn(); - String key = statusBarNotification.getKey(); - int buttonIndex = -1; - // If this is a default template, determine the index of the button. - if (view.getId() == com.android.internal.R.id.action0 && - parent != null && parent instanceof ViewGroup) { - ViewGroup actionGroup = (ViewGroup) parent; - buttonIndex = actionGroup.indexOfChild(view); + return null; } - final int count = mEntryManager.getActiveNotificationsCount(); - final int rank = mEntryManager - .getActiveNotificationUnfiltered(key).getRanking().getRank(); // Notification may be updated before this function is executed, and thus play safe // here and verify that the action object is still the one that where the click happens. + StatusBarNotification statusBarNotification = entry.getSbn(); Notification.Action[] actions = statusBarNotification.getNotification().actions; if (actions == null || actionIndex >= actions.length) { Log.w(TAG, "statusBarNotification.getNotification().actions is null or invalid"); - return; + return null ; } final Notification.Action action = statusBarNotification.getNotification().actions[actionIndex]; if (!Objects.equals(action.actionIntent, actionIntent)) { Log.w(TAG, "actionIntent does not match"); + return null; + } + return action; + } + + private void logActionClick( + View view, + NotificationEntry entry, + PendingIntent actionIntent) { + Notification.Action action = getActionFromView(view, entry, actionIntent); + if (action == null) { return; } + ViewParent parent = view.getParent(); + String key = entry.getSbn().getKey(); + int buttonIndex = -1; + // If this is a default template, determine the index of the button. + if (view.getId() == com.android.internal.R.id.action0 && + parent != null && parent instanceof ViewGroup) { + ViewGroup actionGroup = (ViewGroup) parent; + buttonIndex = actionGroup.indexOfChild(view); + } + final int count = mEntryManager.getActiveNotificationsCount(); + final int rank = mEntryManager + .getActiveNotificationUnfiltered(key).getRanking().getRank(); + NotificationVisibility.NotificationLocation location = NotificationLogger.getNotificationLocation( mEntryManager.getActiveNotificationUnfiltered(key)); @@ -813,11 +824,12 @@ public class NotificationRemoteInputManager implements Dumpable { * * @param view * @param pendingIntent + * @param appRequestedAuth * @param defaultHandler * @return true iff the click was handled */ boolean handleRemoteViewClick(View view, PendingIntent pendingIntent, - ClickHandler defaultHandler); + boolean appRequestedAuth, ClickHandler defaultHandler); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index d798692879f5..8f3033edecbb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -18,7 +18,6 @@ package com.android.systemui.statusbar; import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN_REVERSE; import static com.android.systemui.statusbar.phone.NotificationIconContainer.IconState.NO_VALUE; -import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; import android.content.Context; import android.content.res.Configuration; @@ -26,7 +25,6 @@ import android.content.res.Resources; import android.graphics.Rect; import android.os.SystemProperties; import android.util.AttributeSet; -import android.util.Log; import android.util.MathUtils; import android.view.DisplayCutout; import android.view.View; @@ -36,10 +34,8 @@ import android.view.WindowInsets; import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; @@ -48,14 +44,10 @@ import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.notification.stack.ViewState; -import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationIconContainer; -import javax.inject.Inject; -import javax.inject.Named; - /** * A notification shelf view that is placed inside the notification scroller. It manages the * overflow icons that don't fit into the regular list anymore. @@ -69,7 +61,6 @@ public class NotificationShelf extends ActivatableNotificationView implements = SystemProperties.getBoolean("debug.icon_scroll_animations", true); private static final int TAG_CONTINUOUS_CLIPPING = R.id.continuous_clipping_tag; private static final String TAG = "NotificationShelf"; - private final KeyguardBypassController mBypassController; private NotificationIconContainer mShelfIcons; private int[] mTmp = new int[2]; @@ -77,9 +68,8 @@ public class NotificationShelf extends ActivatableNotificationView implements private int mIconAppearTopPadding; private float mHiddenShelfIconSize; private int mStatusBarHeight; - private int mStatusBarPaddingStart; private AmbientState mAmbientState; - private NotificationStackScrollLayout mHostLayout; + private NotificationStackScrollLayoutController mHostLayoutController; private int mMaxLayoutHeight; private int mPaddingBetweenElements; private int mNotGoneIndex; @@ -88,7 +78,6 @@ public class NotificationShelf extends ActivatableNotificationView implements private int mScrollFastThreshold; private int mIconSize; private int mStatusBarState; - private float mMaxShelfEnd; private int mRelativeOffset; private boolean mInteractive; private float mOpenedAmount; @@ -99,13 +88,10 @@ public class NotificationShelf extends ActivatableNotificationView implements private Rect mClipRect = new Rect(); private int mCutoutHeight; private int mGapHeight; + private NotificationShelfController mController; - @Inject - public NotificationShelf(@Named(VIEW_CONTEXT) Context context, - AttributeSet attrs, - KeyguardBypassController keyguardBypassController) { + public NotificationShelf(Context context, AttributeSet attrs) { super(context, attrs); - mBypassController = keyguardBypassController; } @Override @@ -128,29 +114,16 @@ public class NotificationShelf extends ActivatableNotificationView implements initDimens(); } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class)) - .addCallback(this, SysuiStatusBarStateController.RANK_SHELF); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - Dependency.get(StatusBarStateController.class).removeCallback(this); - } - - public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) { + public void bind(AmbientState ambientState, + NotificationStackScrollLayoutController hostLayoutController) { mAmbientState = ambientState; - mHostLayout = hostLayout; + mHostLayoutController = hostLayoutController; } private void initDimens() { Resources res = getResources(); mIconAppearTopPadding = res.getDimensionPixelSize(R.dimen.notification_icon_appear_padding); mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height); - mStatusBarPaddingStart = res.getDimensionPixelOffset(R.dimen.status_bar_padding_start); mPaddingBetweenElements = res.getDimensionPixelSize(R.dimen.notification_divider_height); ViewGroup.LayoutParams layoutParams = getLayoutParams(); @@ -276,8 +249,8 @@ public class NotificationShelf extends ActivatableNotificationView implements float firstElementRoundness = 0.0f; ActivatableNotificationView previousAnv = null; - for (int i = 0; i < mHostLayout.getChildCount(); i++) { - ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); + for (int i = 0; i < mHostLayoutController.getChildCount(); i++) { + ExpandableView child = (ExpandableView) mHostLayoutController.getChildAt(i); if (!child.needsClippingToShelf() || child.getVisibility() == GONE) { continue; @@ -315,9 +288,7 @@ public class NotificationShelf extends ActivatableNotificationView implements transitionAmount = inShelfAmount; } // We don't want to modify the color if the notification is hun'd - boolean canModifyColor = mAmbientState.isShadeExpanded() - && !(mAmbientState.isOnKeyguard() && mBypassController.getBypassEnabled()); - if (isLastChild && canModifyColor) { + if (isLastChild && mController.canModifyColorOfNotifications()) { if (colorOfViewBeforeLast == NO_COLOR) { colorOfViewBeforeLast = ownColorUntinted; } @@ -384,8 +355,8 @@ public class NotificationShelf extends ActivatableNotificationView implements mShelfIcons.setSpeedBumpIndex(mAmbientState.getSpeedBumpIndex()); mShelfIcons.calculateIconTranslations(); mShelfIcons.applyIconStates(); - for (int i = 0; i < mHostLayout.getChildCount(); i++) { - View child = mHostLayout.getChildAt(i); + for (int i = 0; i < mHostLayoutController.getChildCount(); i++) { + View child = mHostLayoutController.getChildAt(i); if (!(child instanceof ExpandableNotificationRow) || child.getVisibility() == GONE) { continue; @@ -408,8 +379,8 @@ public class NotificationShelf extends ActivatableNotificationView implements * swipes quickly. */ private void clipTransientViews() { - for (int i = 0; i < mHostLayout.getTransientViewCount(); i++) { - View transientView = mHostLayout.getTransientView(i); + for (int i = 0; i < mHostLayoutController.getTransientViewCount(); i++) { + View transientView = mHostLayoutController.getTransientView(i); if (transientView instanceof ExpandableView) { ExpandableView transientExpandableView = (ExpandableView) transientView; updateNotificationClipHeight(transientExpandableView, getTranslationY(), -1); @@ -648,7 +619,7 @@ public class NotificationShelf extends ActivatableNotificationView implements // We need to persist this, since after the expansion, the behavior should still be the // same. float position = mAmbientState.getIntrinsicPadding() - + mHostLayout.getPositionInLinearLayout(view); + + mHostLayoutController.getPositionInLinearLayout(view); int maxShelfStart = mMaxLayoutHeight - getIntrinsicHeight(); if (position < maxShelfStart && position + view.getIntrinsicHeight() >= maxShelfStart && view.getTranslationY() < position) { @@ -999,10 +970,6 @@ public class NotificationShelf extends ActivatableNotificationView implements return mInteractive; } - public void setMaxShelfEnd(float maxShelfEnd) { - mMaxShelfEnd = maxShelfEnd; - } - public void setAnimationsEnabled(boolean enabled) { mAnimationsEnabled = enabled; if (!enabled) { @@ -1044,6 +1011,10 @@ public class NotificationShelf extends ActivatableNotificationView implements updateBackgroundColors(); } + public void setController(NotificationShelfController notificationShelfController) { + mController = notificationShelfController; + } + private class ShelfState extends ExpandableViewState { private float openedAmount; private boolean hasItemsInStableShelf; @@ -1056,7 +1027,6 @@ public class NotificationShelf extends ActivatableNotificationView implements } super.applyToView(view); - setMaxShelfEnd(maxShelfEnd); setOpenedAmount(openedAmount); updateAppearance(); setHasItemsInStableShelf(hasItemsInStableShelf); @@ -1070,7 +1040,6 @@ public class NotificationShelf extends ActivatableNotificationView implements } super.animateTo(child, properties); - setMaxShelfEnd(maxShelfEnd); setOpenedAmount(openedAmount); updateAppearance(); setHasItemsInStableShelf(hasItemsInStableShelf); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java new file mode 100644 index 000000000000..77abcfa848ee --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar; + +import android.view.View; + +import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController; +import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope; +import com.android.systemui.statusbar.notification.stack.AmbientState; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.NotificationIconContainer; +import com.android.systemui.statusbar.phone.StatusBarNotificationPresenter; + +import javax.inject.Inject; + +/** + * Controller class for {@link NotificationShelf}. + */ +@NotificationRowScope +public class NotificationShelfController { + private final NotificationShelf mView; + private final ActivatableNotificationViewController mActivatableNotificationViewController; + private final KeyguardBypassController mKeyguardBypassController; + private final SysuiStatusBarStateController mStatusBarStateController; + private final View.OnAttachStateChangeListener mOnAttachStateChangeListener; + private AmbientState mAmbientState; + + @Inject + public NotificationShelfController(NotificationShelf notificationShelf, + ActivatableNotificationViewController activatableNotificationViewController, + KeyguardBypassController keyguardBypassController, + SysuiStatusBarStateController statusBarStateController) { + mView = notificationShelf; + mActivatableNotificationViewController = activatableNotificationViewController; + mKeyguardBypassController = keyguardBypassController; + mStatusBarStateController = statusBarStateController; + mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + mStatusBarStateController.addCallback( + mView, SysuiStatusBarStateController.RANK_SHELF); + } + + @Override + public void onViewDetachedFromWindow(View v) { + mStatusBarStateController.removeCallback(mView); + } + }; + } + + public void init() { + mActivatableNotificationViewController.init(); + mView.setController(this); + mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener); + if (mView.isAttachedToWindow()) { + mOnAttachStateChangeListener.onViewAttachedToWindow(mView); + } + } + + public NotificationShelf getView() { + return mView; + } + + public boolean canModifyColorOfNotifications() { + return mAmbientState.isShadeExpanded() + && !(mAmbientState.isOnKeyguard() && mKeyguardBypassController.getBypassEnabled()); + } + + public NotificationIconContainer getShelfIcons() { + return mView.getShelfIcons(); + } + + public void setCollapsedIcons(NotificationIconContainer notificationIcons) { + mView.setCollapsedIcons(notificationIcons); + } + + public void bind(AmbientState ambientState, + NotificationStackScrollLayoutController notificationStackScrollLayoutController) { + mView.bind(ambientState, notificationStackScrollLayoutController); + mAmbientState = ambientState; + } + + public int getHeight() { + return mView.getHeight(); + } + + public void updateState(AmbientState ambientState) { + mAmbientState = ambientState; + mView.updateState(ambientState); + } + + public int getIntrinsicHeight() { + return mView.getIntrinsicHeight(); + } + + public void setOnActivatedListener(StatusBarNotificationPresenter presenter) { + mView.setOnActivatedListener(presenter); + } + + public void setOnClickListener(View.OnClickListener onClickListener) { + mView.setOnClickListener(onClickListener); + } + + public int getNotGoneIndex() { + return mView.getNotGoneIndex(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt index 7b2585324b9f..ff13c4e90bba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt @@ -36,7 +36,7 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.phone.HeadsUpManagerPhone import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.ShadeController @@ -93,7 +93,7 @@ constructor( private set private val mTouchSlop: Float private lateinit var expansionCallback: ExpansionCallback - private lateinit var stackScroller: NotificationStackScrollLayout + private lateinit var stackScrollerController: NotificationStackScrollLayoutController private val mTemp2 = IntArray(2) private var mDraggedFarEnough: Boolean = false private var mStartingChild: ExpandableView? = null @@ -315,23 +315,23 @@ constructor( private fun findView(x: Float, y: Float): ExpandableView? { var totalX = x var totalY = y - stackScroller.getLocationOnScreen(mTemp2) + stackScrollerController.getLocationOnScreen(mTemp2) totalX += mTemp2[0].toFloat() totalY += mTemp2[1].toFloat() - val childAtRawPosition = stackScroller.getChildAtRawPosition(totalX, totalY) + val childAtRawPosition = stackScrollerController.getChildAtRawPosition(totalX, totalY) return if (childAtRawPosition != null && childAtRawPosition.isContentExpandable) { childAtRawPosition } else null } fun setUp( - stackScroller: NotificationStackScrollLayout, + stackScrollerController: NotificationStackScrollLayoutController, expansionCallback: ExpansionCallback, shadeController: ShadeController ) { this.expansionCallback = expansionCallback this.shadeController = shadeController - this.stackScroller = stackScroller + this.stackScrollerController = stackScrollerController } fun setPulsing(pulsing: Boolean) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java b/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java index 7cda23544ca0..27e4adee68ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java @@ -21,7 +21,7 @@ import android.view.LayoutInflater; import android.view.ViewGroup; import com.android.systemui.R; -import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; +import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.phone.LockIcon; import com.android.systemui.statusbar.phone.LockscreenLockIconController; import com.android.systemui.statusbar.phone.NotificationPanelView; @@ -41,22 +41,22 @@ public class SuperStatusBarViewFactory { private final Context mContext; private final InjectionInflationController mInjectionInflationController; - private final NotificationRowComponent.Builder mNotificationRowComponentBuilder; private final LockscreenLockIconController mLockIconController; + private final NotificationShelfComponent.Builder mNotificationShelfComponentBuilder; private NotificationShadeWindowView mNotificationShadeWindowView; private StatusBarWindowView mStatusBarWindowView; - private NotificationShelf mNotificationShelf; + private NotificationShelfController mNotificationShelfController; @Inject public SuperStatusBarViewFactory(Context context, InjectionInflationController injectionInflationController, - NotificationRowComponent.Builder notificationRowComponentBuilder, + NotificationShelfComponent.Builder notificationShelfComponentBuilder, LockscreenLockIconController lockIconController) { mContext = context; mInjectionInflationController = injectionInflationController; - mNotificationRowComponentBuilder = notificationRowComponentBuilder; mLockIconController = lockIconController; + mNotificationShelfComponentBuilder = notificationShelfComponentBuilder; } /** @@ -114,25 +114,27 @@ public class SuperStatusBarViewFactory { * isn't immediately attached, but the layout params of this view is used * during inflation. */ - public NotificationShelf getNotificationShelf(ViewGroup container) { - if (mNotificationShelf != null) { - return mNotificationShelf; + public NotificationShelfController getNotificationShelfController(ViewGroup container) { + if (mNotificationShelfController != null) { + return mNotificationShelfController; } - mNotificationShelf = (NotificationShelf) mInjectionInflationController.injectable( - LayoutInflater.from(mContext)).inflate(R.layout.status_bar_notification_shelf, - container, /* attachToRoot= */ false); + NotificationShelf view = (NotificationShelf) LayoutInflater.from(mContext) + .inflate(R.layout.status_bar_notification_shelf, container, /* attachToRoot= */ + false); - NotificationRowComponent component = mNotificationRowComponentBuilder - .activatableNotificationView(mNotificationShelf) - .build(); - component.getActivatableNotificationViewController().init(); - - if (mNotificationShelf == null) { + if (view == null) { throw new IllegalStateException( "R.layout.status_bar_notification_shelf could not be properly inflated"); } - return mNotificationShelf; + + NotificationShelfComponent component = mNotificationShelfComponentBuilder + .notificationShelf(view) + .build(); + mNotificationShelfController = component.getNotificationShelfController(); + mNotificationShelfController.init(); + + return mNotificationShelfController; } public NotificationPanelView getNotificationPanelView() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt index f982cf05de97..0469176255c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt @@ -22,7 +22,7 @@ import com.android.systemui.Interpolators import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.collection.NotificationEntry -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.notification.stack.StackStateAnimator import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.KeyguardBypassController @@ -33,6 +33,7 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener import javax.inject.Inject import javax.inject.Singleton +import kotlin.math.min @Singleton class NotificationWakeUpCoordinator @Inject constructor( @@ -53,7 +54,7 @@ class NotificationWakeUpCoordinator @Inject constructor( return coordinator.mLinearVisibilityAmount } } - private lateinit var mStackScroller: NotificationStackScrollLayout + private lateinit var mStackScrollerController: NotificationStackScrollLayoutController private var mVisibilityInterpolator = Interpolators.FAST_OUT_SLOW_IN_REVERSE private var mLinearDozeAmount: Float = 0.0f @@ -79,7 +80,7 @@ class NotificationWakeUpCoordinator @Inject constructor( if (mNotificationsVisible && !mNotificationsVisibleForExpansion && !bypassController.bypassEnabled) { // We're waking up while pulsing, let's make sure the animation looks nice - mStackScroller.wakeUpFromPulse() + mStackScrollerController.wakeUpFromPulse() } if (bypassController.bypassEnabled && !mNotificationsVisible) { // Let's make sure our huns become visible once we are waking up in case @@ -156,10 +157,10 @@ class NotificationWakeUpCoordinator @Inject constructor( }) } - fun setStackScroller(stackScroller: NotificationStackScrollLayout) { - mStackScroller = stackScroller - pulseExpanding = stackScroller.isPulseExpanding - stackScroller.setOnPulseHeightChangedListener { + fun setStackScroller(stackScrollerController: NotificationStackScrollLayoutController) { + mStackScrollerController = stackScrollerController + pulseExpanding = stackScrollerController.isPulseExpanding + stackScrollerController.setOnPulseHeightChangedListener { val nowExpanding = isPulseExpanding() val changed = nowExpanding != pulseExpanding pulseExpanding = nowExpanding @@ -169,7 +170,7 @@ class NotificationWakeUpCoordinator @Inject constructor( } } - fun isPulseExpanding(): Boolean = mStackScroller.isPulseExpanding + fun isPulseExpanding(): Boolean = mStackScrollerController.isPulseExpanding /** * @param visible should notifications be visible @@ -249,7 +250,7 @@ class NotificationWakeUpCoordinator @Inject constructor( val changed = linear != mLinearDozeAmount mLinearDozeAmount = linear mDozeAmount = eased - mStackScroller.setDozeAmount(mDozeAmount) + mStackScrollerController.setDozeAmount(mDozeAmount) updateHideAmount() if (changed && linear == 0.0f) { setNotificationsVisible(visible = false, animate = false, increaseSpeed = false) @@ -330,18 +331,18 @@ class NotificationWakeUpCoordinator @Inject constructor( } fun getWakeUpHeight(): Float { - return mStackScroller.wakeUpHeight + return mStackScrollerController.wakeUpHeight } private fun updateHideAmount() { - val linearAmount = Math.min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount) - val amount = Math.min(1.0f - mVisibilityAmount, mDozeAmount) - mStackScroller.setHideAmount(linearAmount, amount) + val linearAmount = min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount) + val amount = min(1.0f - mVisibilityAmount, mDozeAmount) + mStackScrollerController.setHideAmount(linearAmount, amount) notificationsFullyHidden = linearAmount == 1.0f } private fun notifyAnimationStart(awake: Boolean) { - mStackScroller.notifyHideAnimationStart(!awake) + mStackScrollerController.notifyHideAnimationStart(!awake) } override fun onDozingChanged(isDozing: Boolean) { @@ -355,7 +356,7 @@ class NotificationWakeUpCoordinator @Inject constructor( * from a pulse and determines how much the notifications are expanded. */ fun setPulseHeight(height: Float): Float { - val overflow = mStackScroller.setPulseHeight(height) + val overflow = mStackScrollerController.setPulseHeight(height) // no overflow for the bypass experience return if (bypassController.bypassEnabled) 0.0f else overflow } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java new file mode 100644 index 000000000000..af8d6ec727d1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.row.dagger; + +import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; +import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; + +import dagger.Binds; +import dagger.BindsInstance; +import dagger.Module; +import dagger.Subcomponent; + +/** + * Dagger subcomponent for NotificationShelf. + */ +@Subcomponent(modules = {ActivatableNotificationViewModule.class, + NotificationShelfComponent.NotificationShelfModule.class}) +@NotificationRowScope +public interface NotificationShelfComponent { + /** + * Builder for {@link NotificationShelfComponent}. + */ + @Subcomponent.Builder + interface Builder { + @BindsInstance + Builder notificationShelf(NotificationShelf view); + NotificationShelfComponent build(); + } + + /** + * Creates a NotificationShelfController. + */ + @NotificationRowScope + NotificationShelfController getNotificationShelfController(); + /** + * Dagger Module that extracts interesting properties from a NotificationShelf. + */ + @Module + abstract class NotificationShelfModule { + + /** NotificationShelf is provided as an instance of ActivatableNotificationView. */ + @Binds + abstract ActivatableNotificationView bindNotificationShelf(NotificationShelf view); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 66a541a923a4..d2f8a39cc8fb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.stack; import static android.service.notification.NotificationStats.DISMISSAL_SHADE; import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL; -import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters; import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT; import static com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.ANCHOR_SCROLLING; @@ -113,6 +112,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -180,8 +180,7 @@ import javax.inject.Named; * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack. */ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAdapter, - NotificationListContainer, ConfigurationListener, Dumpable, - DynamicPrivacyController.Listener { + ConfigurationListener, Dumpable, DynamicPrivacyController.Listener { public static final float BACKGROUND_ALPHA_DIMMED = 0.7f; private static final String TAG = "StackScroller"; @@ -209,11 +208,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private final Paint mBackgroundPaint = new Paint(); private final boolean mShouldDrawNotificationBackground; private boolean mHighPriorityBeforeSpeedBump; - private final boolean mAllowLongPress; private boolean mDismissRtl; private float mExpandedHeight; private int mOwnScrollY; + private View mScrollAnchorView; private int mScrollAnchorViewY; private int mMaxLayoutHeight; @@ -538,6 +537,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private int mGapHeight; private int mWaterfallTopInset; + private NotificationStackScrollLayoutController mController; private SysuiColorExtractor.OnColorsChangedListener mOnColorsChangedListener = (colorExtractor, which) -> { @@ -545,11 +545,23 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd updateDecorViews(useDarkText); }; + private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener = + new ExpandableView.OnHeightChangedListener() { + @Override + public void onHeightChanged(ExpandableView view, boolean needsAnimation) { + onChildHeightChanged(view, needsAnimation); + } + + @Override + public void onReset(ExpandableView view) { + onChildHeightReset(view); + } + }; + @Inject public NotificationStackScrollLayout( @Named(VIEW_CONTEXT) Context context, AttributeSet attrs, - @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, NotificationRoundnessManager notificationRoundnessManager, DynamicPrivacyController dynamicPrivacyController, SysuiStatusBarStateController statusBarStateController, @@ -572,14 +584,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd super(context, attrs, 0, 0); Resources res = getResources(); - mAllowLongPress = allowLongPress; - mRoundnessManager = notificationRoundnessManager; mLockscreenUserManager = notificationLockscreenUserManager; mNotificationGutsManager = notificationGutsManager; mHeadsUpManager = headsUpManager; - mHeadsUpManager.addListener(mRoundnessManager); mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed); mKeyguardBypassController = keyguardBypassController; mFalsingManager = falsingManager; @@ -611,9 +620,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd res.getBoolean(R.bool.config_drawNotificationBackground); mFadeNotificationsOnDismiss = res.getBoolean(R.bool.config_fadeNotificationsOnDismiss); - mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated); - mRoundnessManager.setOnRoundingChangedCallback(this::invalidate); - addOnExpandedHeightChangedListener(mRoundnessManager::setExpanded); mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener); setOutlineProvider(mOutlineProvider); @@ -640,13 +646,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd tunerService.addTunable((key, newValue) -> { if (key.equals(HIGH_PRIORITY)) { mHighPriorityBeforeSpeedBump = "1".equals(newValue); - } else if (key.equals(Settings.Secure.NOTIFICATION_DISMISS_RTL)) { - updateDismissRtlSetting("1".equals(newValue)); - } else if (key.equals(Settings.Secure.NOTIFICATION_HISTORY_ENABLED)) { - updateFooter(); } - }, HIGH_PRIORITY, Settings.Secure.NOTIFICATION_DISMISS_RTL, - Settings.Secure.NOTIFICATION_HISTORY_ENABLED); + }, HIGH_PRIORITY); mFeatureFlags = featureFlags; mNotifPipeline = notifPipeline; @@ -696,7 +697,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - private void updateDismissRtlSetting(boolean dismissRtl) { + void updateDismissRtlSetting(boolean dismissRtl) { mDismissRtl = dismissRtl; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); @@ -714,9 +715,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd inflateEmptyShadeView(); inflateFooterView(); mVisualStabilityManager.setVisibilityLocationProvider(this::isInVisibleLocation); - if (mAllowLongPress) { - setLongPressListener(mNotificationGutsManager::openGuts); - } } /** @@ -840,7 +838,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd Dependency.get(ConfigurationController.class).removeCallback(this); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public NotificationSwipeActionHelper getSwipeActionHelper() { return mSwipeHelper; @@ -1156,14 +1153,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mNoAmbient = noAmbient; } - @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void setChildLocationsChangedListener( NotificationLogger.OnChildLocationsChangedListener listener) { mListener = listener; } - @Override + public void setScrollAnchorView(View scrollAnchorView) { + mScrollAnchorView = scrollAnchorView; + } + @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM) public boolean isInVisibleLocation(NotificationEntry entry) { ExpandableNotificationRow row = entry.getRow(); @@ -1862,7 +1861,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - @Override @ShadeViewRefactor(RefactorComponent.ADAPTER) public ViewGroup getViewParentForNotification(NotificationEntry entry) { return this; @@ -2552,7 +2550,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd previous); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public boolean hasPulsingNotifications() { return mPulsing; @@ -3056,7 +3053,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - @Override public void cleanUpViewStateForEntry(NotificationEntry entry) { View child = entry.getRow(); if (child == mSwipeHelper.getTranslatingParentView()) { @@ -3323,7 +3319,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void onViewAdded(View child) { super.onViewAdded(child); - onViewAddedInternal((ExpandableView) child); + if (child instanceof ExpandableView) { + onViewAddedInternal((ExpandableView) child); + } } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) @@ -3356,9 +3354,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void onViewAddedInternal(ExpandableView child) { + void onViewAddedInternal(ExpandableView child) { + child.setOnHeightChangedListener(mOnChildHeightChangedListener); updateHideSensitiveForChild(child); - child.setOnHeightChangedListener(this); generateAddAnimation(child, false /* fromMoreCard */); updateAnimationState(child); updateChronometerForChild(child); @@ -3380,18 +3378,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd child.setHideSensitiveForIntrinsicHeight(mAmbientState.isHideSensitive()); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer) { onViewRemovedInternal(row, childrenContainer); } - @Override - @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void notifyGroupChildAdded(ExpandableView row) { - onViewAddedInternal(row); - } - @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void setAnimationsEnabled(boolean animationsEnabled) { mAnimationsEnabled = animationsEnabled; @@ -3416,33 +3407,29 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - private void updateAnimationState(View child) { + void updateAnimationState(View child) { updateAnimationState((mAnimationsEnabled || hasPulsingNotifications()) && (mIsExpanded || isPinnedHeadsUp(child)), child); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setExpandingNotification(ExpandableNotificationRow row) { + void setExpandingNotification(ExpandableNotificationRow row) { mAmbientState.setExpandingNotification(row); requestChildrenUpdate(); } - @Override @ShadeViewRefactor(RefactorComponent.ADAPTER) - public void bindRow(ExpandableNotificationRow row) { + void bindRow(ExpandableNotificationRow row) { row.setHeadsUpAnimatingAwayListener(animatingAway -> { mRoundnessManager.onHeadsupAnimatingAwayChanged(row, animatingAway); mHeadsUpAppearanceController.updateHeader(row.getEntry()); }); } - @Override public boolean containsView(View v) { return v.getParent() == this; } - @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void applyExpandAnimationParams(ExpandAnimationParameters params) { mAmbientState.setExpandAnimationTopChange(params == null ? 0 : params.getTopChange()); @@ -3458,12 +3445,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public boolean isAddOrRemoveAnimationPending() { + boolean isAddOrRemoveAnimationPending() { return mNeedsAnimation && (!mChildrenToAddAnimated.isEmpty() || !mChildrenToRemoveAnimated.isEmpty()); } - @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) { if (mIsExpanded && mAnimationsEnabled && !mChangePositionInProgress && !isFullyHidden()) { @@ -3481,7 +3467,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void changeViewPosition(ExpandableView child, int newIndex) { Assert.isMainThread(); @@ -4477,12 +4462,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - public int getEmptyBottomMargin() { + int getEmptyBottomMargin() { return Math.max(mMaxLayoutHeight - mContentHeight, 0); } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void checkSnoozeLeavebehind() { + void checkSnoozeLeavebehind() { if (mCheckForLeavebehind) { mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */, @@ -4492,19 +4477,19 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void resetCheckSnoozeLeavebehind() { + void resetCheckSnoozeLeavebehind() { mCheckForLeavebehind = true; } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void onExpansionStarted() { + void onExpansionStarted() { mIsExpansionChanging = true; mAmbientState.setExpansionChanging(true); checkSnoozeLeavebehind(); } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void onExpansionStopped() { + void onExpansionStopped() { mIsExpansionChanging = false; resetCheckSnoozeLeavebehind(); mAmbientState.setExpansionChanging(false); @@ -4553,20 +4538,20 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void onPanelTrackingStarted() { + void onPanelTrackingStarted() { mPanelTracking = true; mAmbientState.setPanelTracking(true); resetExposedMenuView(true /* animate */, true /* force */); } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void onPanelTrackingStopped() { + void onPanelTrackingStopped() { mPanelTracking = false; mAmbientState.setPanelTracking(false); } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void resetScrollPosition() { + void resetScrollPosition() { mScroller.abortAnimation(); if (ANCHOR_SCROLLING) { // TODO: once we're recycling this will need to modify the adapter position instead @@ -4607,15 +4592,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void updateChronometerForChild(View child) { + void updateChronometerForChild(View child) { if (child instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) child; row.setChronometerRunning(mIsExpanded); } } - @Override - public void onHeightChanged(ExpandableView view, boolean needsAnimation) { + void onChildHeightChanged(ExpandableView view, boolean needsAnimation) { updateContentHeight(); updateScrollPositionOnExpandInBottom(view); clampScrollPosition(); @@ -4638,8 +4622,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd requestChildrenUpdate(); } - @Override - public void onReset(ExpandableView view) { + void onChildHeightReset(ExpandableView view) { updateAnimationState(view); updateChronometerForChild(view); } @@ -4680,13 +4663,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setOnHeightChangedListener( + void setOnHeightChangedListener( ExpandableView.OnHeightChangedListener onHeightChangedListener) { this.mOnHeightChangedListener = onHeightChangedListener; } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void onChildAnimationFinished() { + void onChildAnimationFinished() { setAnimationRunning(false); requestChildrenUpdate(); runAnimationFinishedRunnables(); @@ -4730,7 +4713,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * See {@link AmbientState#setDimmed}. */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setDimmed(boolean dimmed, boolean animate) { + void setDimmed(boolean dimmed, boolean animate) { dimmed &= onKeyguard(); mAmbientState.setDimmed(dimmed); if (animate && mAnimationsEnabled) { @@ -4795,7 +4778,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * See {@link AmbientState#setActivatedChild}. */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setActivatedChild(ActivatableNotificationView activatedChild) { + void setActivatedChild(ActivatableNotificationView activatedChild) { mAmbientState.setActivatedChild(activatedChild); if (mAnimationsEnabled) { mActivateNeedsAnimation = true; @@ -4871,7 +4854,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * @param lightTheme True if light theme should be used. */ @ShadeViewRefactor(RefactorComponent.DECORATOR) - public void updateDecorViews(boolean lightTheme) { + private void updateDecorViews(boolean lightTheme) { if (lightTheme == mUsingLightTheme) { return; } @@ -4886,7 +4869,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void goToFullShade(long delay) { + void goToFullShade(long delay) { mGoToFullShadeNeedsAnimation = true; mGoToFullShadeDelay = delay; mNeedsAnimation = true; @@ -4899,13 +4882,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - public void setIntrinsicPadding(int intrinsicPadding) { + void setIntrinsicPadding(int intrinsicPadding) { mIntrinsicPadding = intrinsicPadding; mAmbientState.setIntrinsicPadding(intrinsicPadding); } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - public int getIntrinsicPadding() { + int getIntrinsicPadding() { return mIntrinsicPadding; } @@ -4939,7 +4922,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * animation curve. */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setHideAmount(float linearHideAmount, float interpolatedHideAmount) { + void setHideAmount(float linearHideAmount, float interpolatedHideAmount) { mLinearHideAmount = linearHideAmount; mInterpolatedHideAmount = interpolatedHideAmount; boolean wasFullyHidden = mAmbientState.isFullyHidden(); @@ -4981,7 +4964,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void notifyHideAnimationStart(boolean hide) { + void notifyHideAnimationStart(boolean hide) { // We only swap the scaling factor if we're fully hidden or fully awake to avoid // interpolation issues when playing with the power button. if (mInterpolatedHideAmount == 0 || mInterpolatedHideAmount == 1) { @@ -5009,7 +4992,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setFooterView(@NonNull FooterView footerView) { + void setFooterView(@NonNull FooterView footerView) { int index = -1; if (mFooterView != null) { index = indexOfChild(mFooterView); @@ -5020,7 +5003,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setEmptyShadeView(EmptyShadeView emptyShadeView) { + void setEmptyShadeView(EmptyShadeView emptyShadeView) { int index = -1; if (mEmptyShadeView != null) { index = indexOfChild(mEmptyShadeView); @@ -5031,7 +5014,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void updateEmptyShadeView(boolean visible) { + void updateEmptyShadeView(boolean visible) { mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled); int oldTextRes = mEmptyShadeView.getTextResource(); @@ -5215,33 +5198,28 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public int getContainerChildCount() { return getChildCount(); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public View getContainerChildAt(int i) { return getChildAt(i); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void removeContainerView(View v) { Assert.isMainThread(); removeView(v); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void addContainerView(View v) { Assert.isMainThread(); addView(v); } - @Override public void addContainerViewAt(View v, int index) { Assert.isMainThread(); addView(v, index); @@ -5283,7 +5261,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd requestChildrenUpdate(); } - @Override public void setWillExpand(boolean willExpand) { mWillExpand = willExpand; } @@ -5419,28 +5396,23 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setShelf(NotificationShelf shelf) { + public void setShelfController(NotificationShelfController notificationShelfController) { int index = -1; if (mShelf != null) { index = indexOfChild(mShelf); removeView(mShelf); } - mShelf = shelf; + mShelf = notificationShelfController.getView(); addView(mShelf, index); - mAmbientState.setShelf(shelf); - mStateAnimator.setShelf(shelf); - shelf.bind(mAmbientState, this); + mAmbientState.setShelf(mShelf); + mStateAnimator.setShelf(mShelf); + notificationShelfController.bind(mAmbientState, mController); if (ANCHOR_SCROLLING) { mScrollAnchorView = mShelf; } } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public NotificationShelf getNotificationShelf() { - return mShelf; - } - - @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void setMaxDisplayedNotifications(int maxDisplayedNotifications) { if (mMaxDisplayedNotifications != maxDisplayedNotifications) { mMaxDisplayedNotifications = maxDisplayedNotifications; @@ -5753,7 +5725,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - @Override public void setNotificationActivityStarter( NotificationActivityStarter notificationActivityStarter) { mNotificationActivityStarter = notificationActivityStarter; @@ -5908,6 +5879,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd return MathUtils.smoothStep(0, totalDistance, dragDownAmount); } + public void setController( + NotificationStackScrollLayoutController notificationStackScrollLayoutController) { + mController = notificationStackScrollLayoutController; + mController.getNoticationRoundessManager().setAnimatedChildren(mChildrenToAddAnimated); + } + + public NotificationStackScrollLayoutController getController() { + return mController; + } + /** * A listener that is notified when the empty space below the notifications is clicked on */ @@ -6002,7 +5983,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void resetExposedMenuView(boolean animate, boolean force) { mSwipeHelper.resetExposedMenuView(animate, force); @@ -6754,7 +6734,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } changedRow.setChildrenExpanded(expanded, animated); if (!mGroupExpandedForMeasure) { - onHeightChanged(changedRow, false /* needsAnimation */); + onChildHeightChanged(changedRow, false /* needsAnimation */); } runAfterAnimationFinished(new Runnable() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java new file mode 100644 index 000000000000..e724e65e98a2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -0,0 +1,713 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.stack; + +import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; +import static com.android.systemui.statusbar.phone.NotificationIconAreaController.HIGH_PRIORITY; + +import android.graphics.PointF; +import android.provider.Settings; +import android.view.Display; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowInsets; +import android.widget.FrameLayout; + +import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; +import com.android.systemui.statusbar.NotificationShelfController; +import com.android.systemui.statusbar.RemoteInputController; +import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; +import com.android.systemui.statusbar.notification.NotificationActivityStarter; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.ExpandableView; +import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; +import com.android.systemui.statusbar.phone.HeadsUpTouchHelper; +import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.phone.NotificationIconAreaController; +import com.android.systemui.statusbar.phone.NotificationPanelViewController; +import com.android.systemui.statusbar.phone.ScrimController; +import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.tuner.TunerService; + +import java.util.function.BiConsumer; + +import javax.inject.Inject; +import javax.inject.Named; + +/** + * Controller for {@link NotificationStackScrollLayout}. + */ +@StatusBarComponent.StatusBarScope +public class NotificationStackScrollLayoutController { + private final boolean mAllowLongPress; + private final NotificationGutsManager mNotificationGutsManager; + private final HeadsUpManagerPhone mHeadsUpManager; + private final NotificationRoundnessManager mNotificationRoundnessManager; + private final TunerService mTunerService; + private final NotificationListContainerImpl mNotificationListContainer = + new NotificationListContainerImpl(); + private NotificationStackScrollLayout mView; + + @Inject + public NotificationStackScrollLayoutController( + @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, + NotificationGutsManager notificationGutsManager, + HeadsUpManagerPhone headsUpManager, + NotificationRoundnessManager notificationRoundnessManager, + TunerService tunerService) { + mAllowLongPress = allowLongPress; + mNotificationGutsManager = notificationGutsManager; + mHeadsUpManager = headsUpManager; + mNotificationRoundnessManager = notificationRoundnessManager; + mTunerService = tunerService; + } + + public void attach(NotificationStackScrollLayout view) { + mView = view; + mView.setController(this); + + if (mAllowLongPress) { + mView.setLongPressListener(mNotificationGutsManager::openGuts); + } + + mHeadsUpManager.addListener(mNotificationRoundnessManager); // TODO: why is this here? + + mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate); + mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded); + + mTunerService.addTunable((key, newValue) -> { + if (key.equals(Settings.Secure.NOTIFICATION_DISMISS_RTL)) { + mView.updateDismissRtlSetting("1".equals(newValue)); + } + }, HIGH_PRIORITY, Settings.Secure.NOTIFICATION_DISMISS_RTL); + } + + public void addOnExpandedHeightChangedListener(BiConsumer<Float, Float> listener) { + mView.addOnExpandedHeightChangedListener(listener); + } + + public void removeOnExpandedHeightChangedListener(BiConsumer<Float, Float> listener) { + mView.removeOnExpandedHeightChangedListener(listener); + } + + public void addOnLayoutChangeListener(View.OnLayoutChangeListener listener) { + mView.addOnLayoutChangeListener(listener); + } + + public void removeOnLayoutChangeListener(View.OnLayoutChangeListener listener) { + mView.removeOnLayoutChangeListener(listener); + } + + public void setHeadsUpAppearanceController(HeadsUpAppearanceController controller) { + mView.setHeadsUpAppearanceController(controller); + } + + public void requestLayout() { + mView.requestLayout(); + } + + public Display getDisplay() { + return mView.getDisplay(); + } + + public WindowInsets getRootWindowInsets() { + return mView.getRootWindowInsets(); + } + + public int getRight() { + return mView.getRight(); + } + + public boolean isLayoutRtl() { + return mView.isLayoutRtl(); + } + + public float getLeft() { + return mView.getLeft(); + } + + public float getTranslationX() { + return mView.getTranslationX(); + } + + public void setOnHeightChangedListener( + ExpandableView.OnHeightChangedListener listener) { + mView.setOnHeightChangedListener(listener); + } + + public void setOverscrollTopChangedListener( + NotificationStackScrollLayout.OnOverscrollTopChangedListener listener) { + mView.setOverscrollTopChangedListener(listener); + } + + public void setOnEmptySpaceClickListener( + NotificationStackScrollLayout.OnEmptySpaceClickListener listener) { + mView.setOnEmptySpaceClickListener(listener); + } + + public void setTrackingHeadsUp(ExpandableNotificationRow expandableNotificationRow) { + mView.setTrackingHeadsUp(expandableNotificationRow); + } + + public void wakeUpFromPulse() { + mView.wakeUpFromPulse(); + } + + public boolean isPulseExpanding() { + return mView.isPulseExpanding(); + } + + public void setOnPulseHeightChangedListener(Runnable listener) { + mView.setOnPulseHeightChangedListener(listener); + } + + public void setDozeAmount(float amount) { + mView.setDozeAmount(amount); + } + + public float getWakeUpHeight() { + return mView.getWakeUpHeight(); + } + + public void setHideAmount(float linearAmount, float amount) { + mView.setHideAmount(linearAmount, amount); + } + + public void notifyHideAnimationStart(boolean hide) { + mView.notifyHideAnimationStart(hide); + } + + public float setPulseHeight(float height) { + return mView.setPulseHeight(height); + } + + public void getLocationOnScreen(int[] outLocation) { + mView.getLocationOnScreen(outLocation); + } + + public ExpandableView getChildAtRawPosition(float x, float y) { + return mView.getChildAtRawPosition(x, y); + } + + public FrameLayout.LayoutParams getLayoutParams() { + return (FrameLayout.LayoutParams) mView.getLayoutParams(); + } + + public void setLayoutParams(FrameLayout.LayoutParams lp) { + mView.setLayoutParams(lp); + } + + public void setIsFullWidth(boolean isFullWidth) { + mView.setIsFullWidth(isFullWidth); + } + + public boolean isAddOrRemoveAnimationPending() { + return mView.isAddOrRemoveAnimationPending(); + } + + public int getVisibleNotificationCount() { + return mView.getVisibleNotificationCount(); + } + + public int getIntrinsicContentHeight() { + return mView.getIntrinsicContentHeight(); + } + + public void setIntrinsicPadding(int intrinsicPadding) { + mView.setIntrinsicPadding(intrinsicPadding); + } + + public int getHeight() { + return mView.getHeight(); + } + + public int getChildCount() { + return mView.getChildCount(); + } + + public ExpandableView getChildAt(int i) { + return (ExpandableView) mView.getChildAt(i); + } + + public void goToFullShade(long delay) { + mView.goToFullShade(delay); + } + + public void setOverScrollAmount(float amount, boolean onTop, boolean animate, + boolean cancelAnimators) { + mView.setOverScrollAmount(amount, onTop, animate, cancelAnimators); + } + + public void setOverScrollAmount(float amount, boolean onTop, boolean animate) { + mView.setOverScrollAmount(amount, onTop, animate); + } + + public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) { + mView.setOverScrolledPixels(numPixels, onTop, animate); + } + + public void resetScrollPosition() { + mView.resetScrollPosition(); + } + + public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) { + mView.setShouldShowShelfOnly(shouldShowShelfOnly); + } + + public void cancelLongPress() { + mView.cancelLongPress(); + } + + public float getX() { + return mView.getX(); + } + + public boolean isBelowLastNotification(float x, float y) { + return mView.isBelowLastNotification(x, y); + } + + public float getWidth() { + return mView.getWidth(); + } + + public float getOpeningHeight() { + return mView.getOpeningHeight(); + } + + public float getBottomMostNotificationBottom() { + return mView.getBottomMostNotificationBottom(); + } + + public void checkSnoozeLeavebehind() { + mView.checkSnoozeLeavebehind(); + } + + public void setQsExpanded(boolean expanded) { + mView.setQsExpanded(expanded); + } + + public void setScrollingEnabled(boolean enabled) { + mView.setScrollingEnabled(enabled); + } + + public void setQsExpansionFraction(float expansionFraction) { + mView.setQsExpansionFraction(expansionFraction); + } + + public float calculateAppearFractionBypass() { + return mView.calculateAppearFractionBypass(); + } + + public void updateTopPadding(float qsHeight, boolean animate) { + mView.updateTopPadding(qsHeight, animate); + } + + public void resetCheckSnoozeLeavebehind() { + mView.resetCheckSnoozeLeavebehind(); + } + + public boolean isScrolledToBottom() { + return mView.isScrolledToBottom(); + } + + public int getNotGoneChildCount() { + return mView.getNotGoneChildCount(); + } + + public float getIntrinsicPadding() { + return mView.getIntrinsicPadding(); + } + + public float getLayoutMinHeight() { + return mView.getLayoutMinHeight(); + } + + public int getEmptyBottomMargin() { + return mView.getEmptyBottomMargin(); + } + + public float getTopPaddingOverflow() { + return mView.getTopPaddingOverflow(); + } + + public int getTopPadding() { + return mView.getTopPadding(); + } + + public float getEmptyShadeViewHeight() { + return mView.getEmptyShadeViewHeight(); + } + + public void setAlpha(float alpha) { + mView.setAlpha(alpha); + } + + public float getCurrentOverScrollAmount(boolean top) { + return mView.getCurrentOverScrollAmount(top); + } + + public float getCurrentOverScrolledPixels(boolean top) { + return mView.getCurrentOverScrolledPixels(top); + } + + public float calculateAppearFraction(float height) { + return mView.calculateAppearFraction(height); + } + + public void onExpansionStarted() { + mView.onExpansionStarted(); + } + + public void onExpansionStopped() { + mView.onExpansionStopped(); + } + + public void onPanelTrackingStarted() { + mView.onPanelTrackingStarted(); + } + + public void onPanelTrackingStopped() { + mView.onPanelTrackingStopped(); + } + + public void setHeadsUpBoundaries(int height, int bottomBarHeight) { + mView.setHeadsUpBoundaries(height, bottomBarHeight); + } + + public void setUnlockHintRunning(boolean running) { + mView.setUnlockHintRunning(running); + } + + public float getPeekHeight() { + return mView.getPeekHeight(); + } + + public boolean isFooterViewNotGone() { + return mView.isFooterViewNotGone(); + } + + public boolean isFooterViewContentVisible() { + return mView.isFooterViewContentVisible(); + } + + public int getFooterViewHeightWithPadding() { + return mView.getFooterViewHeightWithPadding(); + } + + public void updateEmptyShadeView(boolean visible) { + mView.updateEmptyShadeView(visible); + } + + public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { + mView.setHeadsUpAnimatingAway(headsUpAnimatingAway); + } + + public HeadsUpTouchHelper.Callback getHeadsUpCallback() { + return mView.getHeadsUpCallback(); + } + + public void forceNoOverlappingRendering(boolean force) { + mView.forceNoOverlappingRendering(force); + } + + public void setTranslationX(float translation) { + mView.setTranslationX(translation); + } + + public void setExpandingVelocity(float velocity) { + mView.setExpandingVelocity(velocity); + } + + public void setExpandedHeight(float expandedHeight) { + mView.setExpandedHeight(expandedHeight); + } + + public void setQsContainer(ViewGroup view) { + mView.setQsContainer(view); + } + + public void setAnimationsEnabled(boolean enabled) { + mView.setAnimationsEnabled(enabled); + } + + public void setDozing(boolean dozing, boolean animate, PointF wakeUpTouchLocation) { + mView.setDozing(dozing, animate, wakeUpTouchLocation); + } + + public void setPulsing(boolean pulsing, boolean animatePulse) { + mView.setPulsing(pulsing, animatePulse); + } + + public boolean hasActiveClearableNotifications( + @NotificationStackScrollLayout.SelectedRows int selection) { + return mView.hasActiveClearableNotifications(selection); + } + + public RemoteInputController.Delegate createDelegate() { + return mView.createDelegate(); + } + + public void updateSectionBoundaries(String reason) { + mView.updateSectionBoundaries(reason); + } + + public void updateSpeedBumpIndex() { + mView.updateSpeedBumpIndex(); + } + + public void updateFooter() { + mView.updateFooter(); + } + + public void updateIconAreaViews() { + mView.updateIconAreaViews(); + } + + public void onUpdateRowStates() { + mView.onUpdateRowStates(); + } + + public ActivatableNotificationView getActivatedChild() { + return mView.getActivatedChild(); + } + + public void setActivatedChild(ActivatableNotificationView view) { + mView.setActivatedChild(view); + } + + public void runAfterAnimationFinished(Runnable r) { + mView.runAfterAnimationFinished(r); + } + + public void setNotificationPanelController( + NotificationPanelViewController notificationPanelViewController) { + mView.setNotificationPanelController(notificationPanelViewController); + } + + public void setIconAreaController(NotificationIconAreaController controller) { + mView.setIconAreaController(controller); + } + + public void setStatusBar(StatusBar statusBar) { + mView.setStatusBar(statusBar); + } + + public void setGroupManager(NotificationGroupManager groupManager) { + mView.setGroupManager(groupManager); + } + + public void setShelfController(NotificationShelfController notificationShelfController) { + mView.setShelfController(notificationShelfController); + } + + public void setScrimController(ScrimController scrimController) { + mView.setScrimController(scrimController); + } + + public ExpandableView getFirstChildNotGone() { + return mView.getFirstChildNotGone(); + } + + public void setInHeadsUpPinnedMode(boolean inPinnedMode) { + mView.setInHeadsUpPinnedMode(inPinnedMode); + } + + public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) { + mView.generateHeadsUpAnimation(entry, isHeadsUp); + } + + public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) { + mView.generateHeadsUpAnimation(row, isHeadsUp); + } + + public void setMaxTopPadding(int padding) { + mView.setMaxTopPadding(padding); + } + + public int getTransientViewCount() { + return mView.getTransientViewCount(); + } + + public View getTransientView(int i) { + return mView.getTransientView(i); + } + + public int getPositionInLinearLayout(ExpandableView row) { + return mView.getPositionInLinearLayout(row); + } + + public NotificationStackScrollLayout getView() { + return mView; + } + + public float calculateGapHeight(ExpandableView previousView, ExpandableView child, int count) { + return mView.calculateGapHeight(previousView, child, count); + } + + public NotificationRoundnessManager getNoticationRoundessManager() { + return mNotificationRoundnessManager; + } + + public NotificationListContainer getNotificationListContainer() { + return mNotificationListContainer; + } + + private class NotificationListContainerImpl implements NotificationListContainer { + @Override + public void setChildTransferInProgress(boolean childTransferInProgress) { + mView.setChildTransferInProgress(childTransferInProgress); + } + + @Override + public void changeViewPosition(ExpandableView child, int newIndex) { + mView.changeViewPosition(child, newIndex); + } + + @Override + public void notifyGroupChildAdded(ExpandableView row) { + mView.onViewAddedInternal(row); + } + + @Override + public void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer) { + mView.notifyGroupChildRemoved(row, childrenContainer); + } + + @Override + public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) { + mView.generateAddAnimation(child, fromMoreCard); + } + + @Override + public void generateChildOrderChangedEvent() { + mView.generateChildOrderChangedEvent(); + } + + @Override + public int getContainerChildCount() { + return mView.getContainerChildCount(); + } + + @Override + public void setNotificationActivityStarter( + NotificationActivityStarter notificationActivityStarter) { + mView.setNotificationActivityStarter(notificationActivityStarter); + } + + @Override + public View getContainerChildAt(int i) { + return mView.getContainerChildAt(i); + } + + @Override + public void removeContainerView(View v) { + mView.removeContainerView(v); + } + + @Override + public void addContainerView(View v) { + mView.addContainerView(v); + } + + @Override + public void addContainerViewAt(View v, int index) { + mView.addContainerViewAt(v, index); + } + + @Override + public void setMaxDisplayedNotifications(int maxNotifications) { + mView.setMaxDisplayedNotifications(maxNotifications); + } + + @Override + public ViewGroup getViewParentForNotification(NotificationEntry entry) { + return mView.getViewParentForNotification(entry); + } + + @Override + public void resetExposedMenuView(boolean animate, boolean force) { + mView.resetExposedMenuView(animate, force); + } + + @Override + public NotificationSwipeActionHelper getSwipeActionHelper() { + return mView.getSwipeActionHelper(); + } + + @Override + public void cleanUpViewStateForEntry(NotificationEntry entry) { + mView.cleanUpViewStateForEntry(entry); + } + + @Override + public void setChildLocationsChangedListener( + NotificationLogger.OnChildLocationsChangedListener listener) { + + } + + public boolean hasPulsingNotifications() { + return mView.hasPulsingNotifications(); + } + + @Override + public boolean isInVisibleLocation(NotificationEntry entry) { + return mView.isInVisibleLocation(entry); + } + + @Override + public void onHeightChanged(ExpandableView view, boolean needsAnimation) { + mView.onChildHeightChanged(view, needsAnimation); + } + + @Override + public void onReset(ExpandableView view) { + mView.onChildHeightReset(view); + } + + @Override + public void bindRow(ExpandableNotificationRow row) { + mView.bindRow(row); + } + + @Override + public void applyExpandAnimationParams( + ActivityLaunchAnimator.ExpandAnimationParameters params) { + mView.applyExpandAnimationParams(params); + } + + @Override + public void setExpandingNotification(ExpandableNotificationRow row) { + mView.setExpandingNotification(row); + } + + @Override + public boolean containsView(View v) { + return mView.containsView(v); + } + + @Override + public void setWillExpand(boolean willExpand) { + mView.setWillExpand(willExpand); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java index 51c02c9f93ab..8cdaa63994e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java @@ -36,7 +36,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; @@ -52,7 +52,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, public static final int CONTENT_FADE_DELAY = 100; private final NotificationIconAreaController mNotificationIconAreaController; private final HeadsUpManagerPhone mHeadsUpManager; - private final NotificationStackScrollLayout mStackScroller; + private final NotificationStackScrollLayoutController mStackScrollerController; private final HeadsUpStatusBarView mHeadsUpStatusBarView; private final View mCenteredIconView; private final View mClockView; @@ -93,7 +93,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, public HeadsUpAppearanceController( NotificationIconAreaController notificationIconAreaController, HeadsUpManagerPhone headsUpManager, - View notificationShadeView, + NotificationStackScrollLayoutController notificationStackScrollLayoutController, SysuiStatusBarStateController statusBarStateController, KeyguardBypassController keyguardBypassController, KeyguardStateController keyguardStateController, @@ -101,10 +101,9 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, NotificationPanelViewController notificationPanelViewController, View statusBarView) { this(notificationIconAreaController, headsUpManager, statusBarStateController, keyguardBypassController, wakeUpCoordinator, keyguardStateController, - commandQueue, - statusBarView.findViewById(R.id.heads_up_status_bar_view), - notificationShadeView.findViewById(R.id.notification_stack_scroller), + commandQueue, notificationStackScrollLayoutController, notificationPanelViewController, + statusBarView.findViewById(R.id.heads_up_status_bar_view), statusBarView.findViewById(R.id.clock), statusBarView.findViewById(R.id.operator_name_frame), statusBarView.findViewById(R.id.centered_icon_area)); @@ -119,9 +118,9 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, NotificationWakeUpCoordinator wakeUpCoordinator, KeyguardStateController keyguardStateController, CommandQueue commandQueue, - HeadsUpStatusBarView headsUpStatusBarView, - NotificationStackScrollLayout stackScroller, + NotificationStackScrollLayoutController stackScrollerController, NotificationPanelViewController notificationPanelViewController, + HeadsUpStatusBarView headsUpStatusBarView, View clockView, View operatorNameView, View centeredIconView) { @@ -132,14 +131,14 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, mCenteredIconView = centeredIconView; headsUpStatusBarView.setOnDrawingRectChangedListener( () -> updateIsolatedIconLocation(true /* requireUpdate */)); - mStackScroller = stackScroller; + mStackScrollerController = stackScrollerController; mNotificationPanelViewController = notificationPanelViewController; notificationPanelViewController.addTrackingHeadsUpListener(mSetTrackingHeadsUp); notificationPanelViewController.addVerticalTranslationListener(mUpdatePanelTranslation); notificationPanelViewController.setHeadsUpAppearanceController(this); - mStackScroller.addOnExpandedHeightChangedListener(mSetExpandedHeight); - mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener); - mStackScroller.setHeadsUpAppearanceController(this); + mStackScrollerController.addOnExpandedHeightChangedListener(mSetExpandedHeight); + mStackScrollerController.addOnLayoutChangeListener(mStackScrollLayoutChangeListener); + mStackScrollerController.setHeadsUpAppearanceController(this); mClockView = clockView; mOperatorNameView = operatorNameView; mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class); @@ -153,7 +152,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, updateTopEntry(); // trigger scroller to notify the latest panel translation - mStackScroller.requestLayout(); + mStackScrollerController.requestLayout(); } mHeadsUpStatusBarView.removeOnLayoutChangeListener(this); } @@ -174,8 +173,8 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, mNotificationPanelViewController.removeTrackingHeadsUpListener(mSetTrackingHeadsUp); mNotificationPanelViewController.removeVerticalTranslationListener(mUpdatePanelTranslation); mNotificationPanelViewController.setHeadsUpAppearanceController(null); - mStackScroller.removeOnExpandedHeightChangedListener(mSetExpandedHeight); - mStackScroller.removeOnLayoutChangeListener(mStackScrollLayoutChangeListener); + mStackScrollerController.removeOnExpandedHeightChangedListener(mSetExpandedHeight); + mStackScrollerController.removeOnLayoutChangeListener(mStackScrollLayoutChangeListener); mDarkIconDispatcher.removeDarkReceiver(this); } @@ -219,12 +218,12 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, } int realDisplaySize = 0; - if (mStackScroller.getDisplay() != null) { - mStackScroller.getDisplay().getRealSize(mPoint); + if (mStackScrollerController.getDisplay() != null) { + mStackScrollerController.getDisplay().getRealSize(mPoint); realDisplaySize = mPoint.x; } - WindowInsets windowInset = mStackScroller.getRootWindowInsets(); + WindowInsets windowInset = mStackScrollerController.getRootWindowInsets(); DisplayCutout cutout = (windowInset != null) ? windowInset.getDisplayCutout() : null; int sysWinLeft = (windowInset != null) ? windowInset.getStableInsetLeft() : 0; int sysWinRight = (windowInset != null) ? windowInset.getStableInsetRight() : 0; @@ -233,17 +232,17 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, int leftInset = Math.max(sysWinLeft, cutoutLeft); int rightInset = Math.max(sysWinRight, cutoutRight); - return leftInset + mStackScroller.getRight() + rightInset - realDisplaySize; + return leftInset + mStackScrollerController.getRight() + rightInset - realDisplaySize; } public void updatePanelTranslation() { float newTranslation; - if (mStackScroller.isLayoutRtl()) { + if (mStackScrollerController.isLayoutRtl()) { newTranslation = getRtlTranslation(); } else { - newTranslation = mStackScroller.getLeft(); + newTranslation = mStackScrollerController.getLeft(); } - newTranslation += mStackScroller.getTranslationX(); + newTranslation += mStackScrollerController.getTranslationX(); mHeadsUpStatusBarView.setPanelTranslation(newTranslation); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 9d3e915cad69..7bbe1c986249 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -26,7 +26,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.NotificationUtils; @@ -160,9 +160,9 @@ public class NotificationIconAreaController implements DarkReceiver, } } - public void setupShelf(NotificationShelf shelf) { - mShelfIcons = shelf.getShelfIcons(); - shelf.setCollapsedIcons(mNotificationIcons); + public void setupShelf(NotificationShelfController notificationShelfController) { + mShelfIcons = notificationShelfController.getShelfIcons(); + notificationShelfController.setCollapsedIcons(mNotificationIcons); } public void onDensityOrFontScaleChanged(Context context) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index a87311a69ab5..42fbe5967d42 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -86,6 +86,7 @@ import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; @@ -105,6 +106,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; @@ -174,6 +176,7 @@ public class NotificationPanelViewController extends PanelViewController { private final ZenModeController mZenModeController; private final ConfigurationController mConfigurationController; private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder; + private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is // changed. @@ -264,7 +267,6 @@ public class NotificationPanelViewController extends PanelViewController { private KeyguardStatusView mKeyguardStatusView; private View mQsNavbarScrim; private NotificationsQuickSettingsContainer mNotificationContainerParent; - private NotificationStackScrollLayout mNotificationStackScroller; private boolean mAnimateNextPositionUpdate; private int mTrackingPointer; @@ -454,6 +456,7 @@ public class NotificationPanelViewController extends PanelViewController { private boolean mAnimatingQS; private int mOldLayoutDirection; + private NotificationShelfController mNotificationShelfController; private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() { @Override @@ -498,7 +501,8 @@ public class NotificationPanelViewController extends PanelViewController { MediaHierarchyManager mediaHierarchyManager, BiometricUnlockController biometricUnlockController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, - Provider<KeyguardClockSwitchController> keyguardClockSwitchControllerProvider) { + Provider<KeyguardClockSwitchController> keyguardClockSwitchControllerProvider, + NotificationStackScrollLayoutController notificationStackScrollLayoutController) { super(view, falsingManager, dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, vibratorHelper, latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager); @@ -511,6 +515,7 @@ public class NotificationPanelViewController extends PanelViewController { mMediaHierarchyManager = mediaHierarchyManager; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mKeyguardClockSwitchControllerProvider = keyguardClockSwitchControllerProvider; + mNotificationStackScrollLayoutController = notificationStackScrollLayoutController; mView.setWillNotDraw(!DEBUG); mInjectionInflationController = injectionInflationController; mFalsingManager = falsingManager; @@ -590,21 +595,26 @@ public class NotificationPanelViewController extends PanelViewController { keyguardClockSwitchController.setBigClockContainer(mBigClockContainer); mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent); - mNotificationStackScroller = mView.findViewById(R.id.notification_stack_scroller); - mNotificationStackScroller.setOnHeightChangedListener(mOnHeightChangedListener); - mNotificationStackScroller.setOverscrollTopChangedListener(mOnOverscrollTopChangedListener); - mNotificationStackScroller.setOnEmptySpaceClickListener(mOnEmptySpaceClickListener); - addTrackingHeadsUpListener(mNotificationStackScroller::setTrackingHeadsUp); + NotificationStackScrollLayout stackScrollLayout = mView.findViewById( + R.id.notification_stack_scroller); + mNotificationStackScrollLayoutController.attach(stackScrollLayout); + mNotificationStackScrollLayoutController.setOnHeightChangedListener( + mOnHeightChangedListener); + mNotificationStackScrollLayoutController.setOverscrollTopChangedListener( + mOnOverscrollTopChangedListener); + mNotificationStackScrollLayoutController.setOnEmptySpaceClickListener( + mOnEmptySpaceClickListener); + addTrackingHeadsUpListener(mNotificationStackScrollLayoutController::setTrackingHeadsUp); mKeyguardBottomArea = mView.findViewById(R.id.keyguard_bottom_area); mQsNavbarScrim = mView.findViewById(R.id.qs_navbar_scrim); mLastOrientation = mResources.getConfiguration().orientation; initBottomArea(); - mWakeUpCoordinator.setStackScroller(mNotificationStackScroller); + mWakeUpCoordinator.setStackScroller(mNotificationStackScrollLayoutController); mQsFrame = mView.findViewById(R.id.qs_frame); mPulseExpansionHandler.setUp( - mNotificationStackScroller, mExpansionCallback, mShadeController); + mNotificationStackScrollLayoutController, mExpansionCallback, mShadeController); mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() { @Override public void onFullyHiddenChanged(boolean isFullyHidden) { @@ -688,11 +698,11 @@ public class NotificationPanelViewController extends PanelViewController { } int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width); - lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams(); + lp = mNotificationStackScrollLayoutController.getLayoutParams(); if (lp.width != panelWidth || lp.gravity != panelGravity) { lp.width = panelWidth; lp.gravity = panelGravity; - mNotificationStackScroller.setLayoutParams(lp); + mNotificationStackScrollLayoutController.setLayoutParams(lp); } } @@ -770,7 +780,7 @@ public class NotificationPanelViewController extends PanelViewController { private void setIsFullWidth(boolean isFullWidth) { mIsFullWidth = isFullWidth; - mNotificationStackScroller.setIsFullWidth(isFullWidth); + mNotificationStackScrollLayoutController.setIsFullWidth(isFullWidth); } private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) { @@ -804,7 +814,7 @@ public class NotificationPanelViewController extends PanelViewController { * showing. */ private void positionClockAndNotifications() { - boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending(); + boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending(); boolean animateClock = animate || mAnimateNextPositionUpdate; int stackScrollerPadding; if (mBarState != StatusBarState.KEYGUARD) { @@ -814,12 +824,12 @@ public class NotificationPanelViewController extends PanelViewController { int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding); int clockPreferredY = mKeyguardStatusView.getClockPreferredY(totalHeight); boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled(); - final boolean - hasVisibleNotifications = - !bypassEnabled && mNotificationStackScroller.getVisibleNotificationCount() != 0; + final boolean hasVisibleNotifications = !bypassEnabled + && mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0; mKeyguardStatusView.setHasVisibleNotifications(hasVisibleNotifications); mClockPositionAlgorithm.setup(mStatusBarMinHeight, totalHeight - bottomPadding, - mNotificationStackScroller.getIntrinsicContentHeight(), getExpandedFraction(), + mNotificationStackScrollLayoutController.getIntrinsicContentHeight(), + getExpandedFraction(), totalHeight, (int) (mKeyguardStatusView.getHeight() - mShelfHeight / 2.0f - mDarkIconSize / 2.0f), clockPreferredY, hasCustomClock(), hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount, @@ -833,7 +843,7 @@ public class NotificationPanelViewController extends PanelViewController { updateClock(); stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded; } - mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding); + mNotificationStackScrollLayoutController.setIntrinsicPadding(stackScrollerPadding); mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX); mStackScrollerMeasuringPass++; @@ -858,36 +868,51 @@ public class NotificationPanelViewController extends PanelViewController { float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding(); int notificationPadding = Math.max( 1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height)); - NotificationShelf shelf = mNotificationStackScroller.getNotificationShelf(); + NotificationShelf shelf = mNotificationShelfController.getView(); float shelfSize = shelf.getVisibility() == View.GONE ? 0 : shelf.getIntrinsicHeight() + notificationPadding; float availableSpace = - mNotificationStackScroller.getHeight() - minPadding - shelfSize - Math.max( - mIndicationBottomPadding, mAmbientIndicationBottomPadding) + mNotificationStackScrollLayoutController.getHeight() - minPadding - shelfSize + - Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding) - mKeyguardStatusView.getLogoutButtonHeight(); int count = 0; ExpandableView previousView = null; - for (int i = 0; i < mNotificationStackScroller.getChildCount(); i++) { - ExpandableView child = (ExpandableView) mNotificationStackScroller.getChildAt(i); + for (int i = 0; i < mNotificationStackScrollLayoutController.getChildCount(); i++) { + ExpandableView child = mNotificationStackScrollLayoutController.getChildAt(i); + if (!(child instanceof ExpandableNotificationRow)) { + continue; + } + ExpandableNotificationRow row = (ExpandableNotificationRow) child; + boolean + suppressedSummary = + mGroupManager != null && mGroupManager.isSummaryOfSuppressedGroup( + row.getEntry().getSbn()); + if (suppressedSummary) { + continue; + } if (!canShowViewOnLockscreen(child)) { continue; } + if (row.isRemoved()) { + continue; + } availableSpace -= child.getMinHeight(true /* ignoreTemporaryStates */); availableSpace -= count == 0 ? 0 : notificationPadding; - availableSpace -= mNotificationStackScroller.calculateGapHeight(previousView, child, - count); + availableSpace -= mNotificationStackScrollLayoutController + .calculateGapHeight(previousView, child, count); previousView = child; if (availableSpace >= 0 && count < maximum) { count++; } else if (availableSpace > -shelfSize) { // if we are exactly the last view, then we can show us still! - for (int j = i + 1; j < mNotificationStackScroller.getChildCount(); j++) { - ExpandableView view = (ExpandableView) mNotificationStackScroller.getChildAt(j); - if (view instanceof ExpandableNotificationRow && - canShowViewOnLockscreen(view)) { + int childCount = mNotificationStackScrollLayoutController.getChildCount(); + for (int j = i + 1; j < childCount; j++) { + ExpandableView view = mNotificationStackScrollLayoutController.getChildAt(j); + if (view instanceof ExpandableNotificationRow + && canShowViewOnLockscreen(view)) { return count; } } @@ -952,7 +977,7 @@ public class NotificationPanelViewController extends PanelViewController { } public void animateToFullShade(long delay) { - mNotificationStackScroller.goToFullShade(delay); + mNotificationStackScrollLayoutController.goToFullShade(delay); mView.requestLayout(); mAnimateNextPositionUpdate = true; } @@ -978,9 +1003,9 @@ public class NotificationPanelViewController extends PanelViewController { } else { closeQs(); } - mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, animate, + mNotificationStackScrollLayoutController.setOverScrollAmount(0f, true /* onTop */, animate, !animate /* cancelAnimators */); - mNotificationStackScroller.resetScrollPosition(); + mNotificationStackScrollLayoutController.resetScrollPosition(); } @Override @@ -991,7 +1016,7 @@ public class NotificationPanelViewController extends PanelViewController { if (mQsExpanded) { mQsExpandImmediate = true; - mNotificationStackScroller.setShouldShowShelfOnly(true); + mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true); } super.collapse(delayed, speedUpFactor); } @@ -1027,7 +1052,7 @@ public class NotificationPanelViewController extends PanelViewController { public void expandWithQs() { if (mQsExpansionEnabled) { mQsExpandImmediate = true; - mNotificationStackScroller.setShouldShowShelfOnly(true); + mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true); } if (isFullyCollapsed()) { expand(true /* animate */); @@ -1088,7 +1113,7 @@ public class NotificationPanelViewController extends PanelViewController { onQsExpansionStarted(); mInitialHeightOnTouch = mQsExpansionHeight; mQsTracking = true; - mNotificationStackScroller.cancelLongPress(); + mNotificationStackScrollLayoutController.cancelLongPress(); } break; case MotionEvent.ACTION_POINTER_UP: @@ -1124,7 +1149,7 @@ public class NotificationPanelViewController extends PanelViewController { mInitialHeightOnTouch = mQsExpansionHeight; mInitialTouchY = y; mInitialTouchX = x; - mNotificationStackScroller.cancelLongPress(); + mNotificationStackScrollLayoutController.cancelLongPress(); return true; } break; @@ -1144,9 +1169,11 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected boolean isInContentBounds(float x, float y) { - float stackScrollerX = mNotificationStackScroller.getX(); - return !mNotificationStackScroller.isBelowLastNotification(x - stackScrollerX, y) - && stackScrollerX < x && x < stackScrollerX + mNotificationStackScroller.getWidth(); + float stackScrollerX = mNotificationStackScrollLayoutController.getX(); + return !mNotificationStackScrollLayoutController + .isBelowLastNotification(x - stackScrollerX, y) + && stackScrollerX < x + && x < stackScrollerX + mNotificationStackScrollLayoutController.getWidth(); } private void initDownStates(MotionEvent event) { @@ -1254,7 +1281,7 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected float getOpeningHeight() { - return mNotificationStackScroller.getOpeningHeight(); + return mNotificationStackScrollLayoutController.getOpeningHeight(); } @@ -1290,7 +1317,7 @@ public class NotificationPanelViewController extends PanelViewController { < mStatusBarMinHeight) { mMetricsLogger.count(COUNTER_PANEL_OPEN_QS, 1); mQsExpandImmediate = true; - mNotificationStackScroller.setShouldShowShelfOnly(true); + mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true); requestPanelHeightUpdate(); // Normally, we start listening when the panel is expanded, but here we need to start @@ -1302,7 +1329,7 @@ public class NotificationPanelViewController extends PanelViewController { private boolean isInQsArea(float x, float y) { return (x >= mQsFrame.getX() && x <= mQsFrame.getX() + mQsFrame.getWidth()) && ( - y <= mNotificationStackScroller.getBottomMostNotificationBottom() + y <= mNotificationStackScrollLayoutController.getBottomMostNotificationBottom() || y <= mQs.getView().getY() + mQs.getView().getHeight()); } @@ -1492,7 +1519,7 @@ public class NotificationPanelViewController extends PanelViewController { float height = mQsExpansionHeight - overscrollAmount; setQsExpansion(height); requestPanelHeightUpdate(); - mNotificationStackScroller.checkSnoozeLeavebehind(); + mNotificationStackScrollLayoutController.checkSnoozeLeavebehind(); // When expanding QS, let's authenticate the user if possible, // this will speed up notification actions. @@ -1665,8 +1692,8 @@ public class NotificationPanelViewController extends PanelViewController { } private void updateQsState() { - mNotificationStackScroller.setQsExpanded(mQsExpanded); - mNotificationStackScroller.setScrollingEnabled( + mNotificationStackScrollLayoutController.setQsExpanded(mQsExpanded); + mNotificationStackScrollLayoutController.setScrollingEnabled( mBarState != StatusBarState.KEYGUARD && (!mQsExpanded || mQsExpansionFromOverscroll)); updateEmptyShadeView(); @@ -1726,7 +1753,7 @@ public class NotificationPanelViewController extends PanelViewController { float qsExpansionFraction = getQsExpansionFraction(); mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation()); mMediaHierarchyManager.setQsExpansion(qsExpansionFraction); - mNotificationStackScroller.setQsExpansionFraction(qsExpansionFraction); + mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction); } private String determineAccessibilityPaneTitle() { @@ -1785,18 +1812,18 @@ public class NotificationPanelViewController extends PanelViewController { return mClockPositionResult.stackScrollerPadding; } int collapsedPosition = mHeadsUpInset; - if (!mNotificationStackScroller.isPulseExpanding()) { + if (!mNotificationStackScrollLayoutController.isPulseExpanding()) { return collapsedPosition; } else { int expandedPosition = mClockPositionResult.stackScrollerPadding; return (int) MathUtils.lerp(collapsedPosition, expandedPosition, - mNotificationStackScroller.calculateAppearFractionBypass()); + mNotificationStackScrollLayoutController.calculateAppearFractionBypass()); } } protected void requestScrollerTopPaddingUpdate(boolean animate) { - mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(), animate); + mNotificationStackScrollLayoutController.updateTopPadding(calculateQsTopPadding(), animate); if (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled()) { // update the position of the header updateQsExpansion(); @@ -1808,7 +1835,7 @@ public class NotificationPanelViewController extends PanelViewController { if (mQs != null) { mQs.setShowCollapsedOnKeyguard( mKeyguardShowing && mKeyguardBypassController.getBypassEnabled() - && mNotificationStackScroller.isPulseExpanding()); + && mNotificationStackScrollLayoutController.isPulseExpanding()); } } @@ -1904,7 +1931,7 @@ public class NotificationPanelViewController extends PanelViewController { public void onAnimationEnd(Animator animation) { mAnimatingQS = false; notifyExpandingFinished(); - mNotificationStackScroller.resetCheckSnoozeLeavebehind(); + mNotificationStackScrollLayoutController.resetCheckSnoozeLeavebehind(); mQsExpansionAnimator = null; if (onFinishRunnable != null) { onFinishRunnable.run(); @@ -1943,8 +1970,8 @@ public class NotificationPanelViewController extends PanelViewController { protected boolean canCollapsePanelOnTouch() { if (!isInSettings()) { return mBarState == StatusBarState.KEYGUARD - || mNotificationStackScroller.isScrolledToBottom() - || mIsPanelCollapseOnQQS; + || mIsPanelCollapseOnQQS + || mNotificationStackScrollLayoutController.isScrolledToBottom(); } else { return true; } @@ -1962,7 +1989,7 @@ public class NotificationPanelViewController extends PanelViewController { private int getMaxPanelHeightNonBypass() { int min = mStatusBarMinHeight; if (!(mBarState == StatusBarState.KEYGUARD) - && mNotificationStackScroller.getNotGoneChildCount() == 0) { + && mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) { int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount()); min = Math.max(min, minHeight); } @@ -1988,7 +2015,7 @@ public class NotificationPanelViewController extends PanelViewController { int position = mClockPositionAlgorithm.getExpandedClockPosition() + mKeyguardStatusView.getHeight(); - if (mNotificationStackScroller.getVisibleNotificationCount() != 0) { + if (mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0) { position += mShelfHeight / 2.0f + mDarkIconSize / 2.0f; } return position; @@ -2027,8 +2054,8 @@ public class NotificationPanelViewController extends PanelViewController { // minimum QS expansion + minStackHeight float panelHeightQsCollapsed = - mNotificationStackScroller.getIntrinsicPadding() - + mNotificationStackScroller.getLayoutMinHeight(); + mNotificationStackScrollLayoutController.getIntrinsicPadding() + + mNotificationStackScrollLayoutController.getLayoutMinHeight(); float panelHeightQsExpanded = calculatePanelHeightQsExpanded(); t = (expandedHeight - panelHeightQsCollapsed) / (panelHeightQsExpanded @@ -2060,16 +2087,16 @@ public class NotificationPanelViewController extends PanelViewController { } private int calculatePanelHeightShade() { - int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin(); - int maxHeight = mNotificationStackScroller.getHeight() - emptyBottomMargin; - maxHeight += mNotificationStackScroller.getTopPaddingOverflow(); + int emptyBottomMargin = mNotificationStackScrollLayoutController.getEmptyBottomMargin(); + int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin; + maxHeight += mNotificationStackScrollLayoutController.getTopPaddingOverflow(); if (mBarState == StatusBarState.KEYGUARD) { int minKeyguardPanelBottom = mClockPositionAlgorithm.getExpandedClockPosition() + mKeyguardStatusView.getHeight() - + mNotificationStackScroller.getIntrinsicContentHeight(); + + mNotificationStackScrollLayoutController.getIntrinsicContentHeight(); return Math.max(maxHeight, minKeyguardPanelBottom); } else { return maxHeight; @@ -2079,15 +2106,16 @@ public class NotificationPanelViewController extends PanelViewController { private int calculatePanelHeightQsExpanded() { float notificationHeight = - mNotificationStackScroller.getHeight() - - mNotificationStackScroller.getEmptyBottomMargin() - - mNotificationStackScroller.getTopPadding(); + mNotificationStackScrollLayoutController.getHeight() + - mNotificationStackScrollLayoutController.getEmptyBottomMargin() + - mNotificationStackScrollLayoutController.getTopPadding(); // When only empty shade view is visible in QS collapsed state, simulate that we would have // it in expanded QS state as well so we don't run into troubles when fading the view in/out // and expanding/collapsing the whole panel from/to quick settings. - if (mNotificationStackScroller.getNotGoneChildCount() == 0 && mShowEmptyShadeView) { - notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight(); + if (mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0 + && mShowEmptyShadeView) { + notificationHeight = mNotificationStackScrollLayoutController.getEmptyShadeViewHeight(); } int maxQsHeight = mQsMaxExpansionHeight; @@ -2102,12 +2130,13 @@ public class NotificationPanelViewController extends PanelViewController { float totalHeight = Math.max(maxQsHeight, mBarState == StatusBarState.KEYGUARD ? mClockPositionResult.stackScrollerPadding : 0) + notificationHeight - + mNotificationStackScroller.getTopPaddingOverflow(); - if (totalHeight > mNotificationStackScroller.getHeight()) { + + mNotificationStackScrollLayoutController.getTopPaddingOverflow(); + if (totalHeight > mNotificationStackScrollLayoutController.getHeight()) { float fullyCollapsedHeight = - maxQsHeight + mNotificationStackScroller.getLayoutMinHeight(); - totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight()); + maxQsHeight + mNotificationStackScrollLayoutController.getLayoutMinHeight(); + totalHeight = Math.max(fullyCollapsedHeight, + mNotificationStackScrollLayoutController.getHeight()); } return (int) totalHeight; } @@ -2122,7 +2151,7 @@ public class NotificationPanelViewController extends PanelViewController { && !mKeyguardBypassController.getBypassEnabled()) { alpha *= mClockPositionResult.clockAlpha; } - mNotificationStackScroller.setAlpha(alpha); + mNotificationStackScrollLayoutController.setAlpha(alpha); } private float getFadeoutAlpha() { @@ -2138,7 +2167,8 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected float getOverExpansionAmount() { - float result = mNotificationStackScroller.getCurrentOverScrollAmount(true /* top */); + float result = mNotificationStackScrollLayoutController + .getCurrentOverScrollAmount(true /* top */); if (isNaN(result)) { Log.wtf(TAG, "OverExpansionAmount is NaN!"); } @@ -2148,7 +2178,8 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected float getOverExpansionPixels() { - return mNotificationStackScroller.getCurrentOverScrolledPixels(true /* top */); + return mNotificationStackScrollLayoutController + .getCurrentOverScrolledPixels(true /* top */); } /** @@ -2165,17 +2196,19 @@ public class NotificationPanelViewController extends PanelViewController { if (mBarState == StatusBarState.KEYGUARD && !mKeyguardBypassController.getBypassEnabled()) { return -mQs.getQsMinExpansionHeight(); } - float appearAmount = mNotificationStackScroller.calculateAppearFraction(mExpandedHeight); + float appearAmount = mNotificationStackScrollLayoutController + .calculateAppearFraction(mExpandedHeight); float startHeight = -mQsExpansionHeight; if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard() - && mNotificationStackScroller.isPulseExpanding()) { + && mNotificationStackScrollLayoutController.isPulseExpanding()) { if (!mPulseExpansionHandler.isExpanding() && !mPulseExpansionHandler.getLeavingLockscreen()) { // If we aborted the expansion we need to make sure the header doesn't reappear // again after the header has animated away appearAmount = 0; } else { - appearAmount = mNotificationStackScroller.calculateAppearFractionBypass(); + appearAmount = mNotificationStackScrollLayoutController + .calculateAppearFractionBypass(); } startHeight = -mQs.getQsMinExpansionHeight(); } @@ -2264,7 +2297,7 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected void onExpandingStarted() { super.onExpandingStarted(); - mNotificationStackScroller.onExpansionStarted(); + mNotificationStackScrollLayoutController.onExpansionStarted(); mIsExpanding = true; mQsExpandedWhenExpandingStarted = mQsFullyExpanded; mMediaHierarchyManager.setCollapsingShadeFromQS(mQsExpandedWhenExpandingStarted && @@ -2282,7 +2315,7 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected void onExpandingFinished() { super.onExpandingFinished(); - mNotificationStackScroller.onExpansionStopped(); + mNotificationStackScrollLayoutController.onExpansionStopped(); mHeadsUpManager.onExpandingFinished(); mConversationNotificationManager.onNotificationPanelExpandStateChanged(isFullyCollapsed()); mIsExpanding = false; @@ -2308,7 +2341,7 @@ public class NotificationPanelViewController extends PanelViewController { setListening(true); } mQsExpandImmediate = false; - mNotificationStackScroller.setShouldShowShelfOnly(false); + mNotificationStackScrollLayoutController.setShouldShowShelfOnly(false); mTwoFingerQsExpandPossible = false; notifyListenersTrackingHeadsUp(null); mExpandingFromHeadsUp = false; @@ -2340,15 +2373,16 @@ public class NotificationPanelViewController extends PanelViewController { return; } if (mBarState != StatusBarState.KEYGUARD) { - mNotificationStackScroller.setOnHeightChangedListener(null); + mNotificationStackScrollLayoutController.setOnHeightChangedListener(null); if (isPixels) { - mNotificationStackScroller.setOverScrolledPixels(overExpansion, true /* onTop */, - false /* animate */); + mNotificationStackScrollLayoutController.setOverScrolledPixels( + overExpansion, true /* onTop */, false /* animate */); } else { - mNotificationStackScroller.setOverScrollAmount(overExpansion, true /* onTop */, - false /* animate */); + mNotificationStackScrollLayoutController.setOverScrollAmount( + overExpansion, true /* onTop */, false /* animate */); } - mNotificationStackScroller.setOnHeightChangedListener(mOnHeightChangedListener); + mNotificationStackScrollLayoutController + .setOnHeightChangedListener(mOnHeightChangedListener); } } @@ -2358,12 +2392,12 @@ public class NotificationPanelViewController extends PanelViewController { super.onTrackingStarted(); if (mQsFullyExpanded) { mQsExpandImmediate = true; - mNotificationStackScroller.setShouldShowShelfOnly(true); + mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true); } if (mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) { mAffordanceHelper.animateHideLeftRightIcon(); } - mNotificationStackScroller.onPanelTrackingStarted(); + mNotificationStackScrollLayoutController.onPanelTrackingStarted(); } @Override @@ -2371,10 +2405,10 @@ public class NotificationPanelViewController extends PanelViewController { mFalsingManager.onTrackingStopped(); super.onTrackingStopped(expand); if (expand) { - mNotificationStackScroller.setOverScrolledPixels(0.0f, true /* onTop */, + mNotificationStackScrollLayoutController.setOverScrolledPixels(0.0f, true /* onTop */, true /* animate */); } - mNotificationStackScroller.onPanelTrackingStopped(); + mNotificationStackScrollLayoutController.onPanelTrackingStopped(); if (expand && (mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED)) { if (!mHintAnimationRunning) { @@ -2384,7 +2418,8 @@ public class NotificationPanelViewController extends PanelViewController { } private void updateMaxHeadsUpTranslation() { - mNotificationStackScroller.setHeadsUpBoundaries(getHeight(), mNavigationBarBottomHeight); + mNotificationStackScrollLayoutController.setHeadsUpBoundaries( + getHeight(), mNavigationBarBottomHeight); } @Override @@ -2400,19 +2435,19 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected void onUnlockHintFinished() { super.onUnlockHintFinished(); - mNotificationStackScroller.setUnlockHintRunning(false); + mNotificationStackScrollLayoutController.setUnlockHintRunning(false); } @Override protected void onUnlockHintStarted() { super.onUnlockHintStarted(); - mNotificationStackScroller.setUnlockHintRunning(true); + mNotificationStackScrollLayoutController.setUnlockHintRunning(true); } @Override protected float getPeekHeight() { - if (mNotificationStackScroller.getNotGoneChildCount() > 0) { - return mNotificationStackScroller.getPeekHeight(); + if (mNotificationStackScrollLayoutController.getNotGoneChildCount() > 0) { + return mNotificationStackScrollLayoutController.getPeekHeight(); } else { return mQsMinExpansionHeight; } @@ -2426,7 +2461,8 @@ public class NotificationPanelViewController extends PanelViewController { } // Let's make sure we're not appearing but the animation will end below the appear. // Otherwise quick settings would jump at the end of the animation. - float fraction = mNotificationStackScroller.calculateAppearFraction(targetHeight); + float fraction = mNotificationStackScrollLayoutController + .calculateAppearFraction(targetHeight); return fraction >= 1.0f; } @@ -2438,18 +2474,19 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected boolean fullyExpandedClearAllVisible() { - return mNotificationStackScroller.isFooterViewNotGone() - && mNotificationStackScroller.isScrolledToBottom() && !mQsExpandImmediate; + return mNotificationStackScrollLayoutController.isFooterViewNotGone() + && mNotificationStackScrollLayoutController.isScrolledToBottom() + && !mQsExpandImmediate; } @Override protected boolean isClearAllVisible() { - return mNotificationStackScroller.isFooterViewContentVisible(); + return mNotificationStackScrollLayoutController.isFooterViewContentVisible(); } @Override protected int getClearAllHeightWithPadding() { - return mNotificationStackScroller.getFooterViewHeightWithPadding(); + return mNotificationStackScrollLayoutController.getFooterViewHeightWithPadding(); } @Override @@ -2500,7 +2537,8 @@ public class NotificationPanelViewController extends PanelViewController { private void updateEmptyShadeView() { // Hide "No notifications" in QS. - mNotificationStackScroller.updateEmptyShadeView(mShowEmptyShadeView && !mQsExpanded); + mNotificationStackScrollLayoutController.updateEmptyShadeView( + mShowEmptyShadeView && !mQsExpanded); } public void setQsScrimEnabled(boolean qsScrimEnabled) { @@ -2591,7 +2629,7 @@ public class NotificationPanelViewController extends PanelViewController { public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { mHeadsUpAnimatingAway = headsUpAnimatingAway; - mNotificationStackScroller.setHeadsUpAnimatingAway(headsUpAnimatingAway); + mNotificationStackScrollLayoutController.setHeadsUpAnimatingAway(headsUpAnimatingAway); updateHeadsUpVisibility(); } @@ -2603,7 +2641,7 @@ public class NotificationPanelViewController extends PanelViewController { public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) { super.setHeadsUpManager(headsUpManager); mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager, - mNotificationStackScroller.getHeadsUpCallback(), + mNotificationStackScrollLayoutController.getHeadsUpCallback(), NotificationPanelViewController.this); } @@ -2625,7 +2663,7 @@ public class NotificationPanelViewController extends PanelViewController { private void setClosingWithAlphaFadeout(boolean closing) { mClosingWithAlphaFadeOut = closing; - mNotificationStackScroller.forceNoOverlappingRendering(closing); + mNotificationStackScrollLayoutController.forceNoOverlappingRendering(closing); } /** @@ -2635,22 +2673,24 @@ public class NotificationPanelViewController extends PanelViewController { * @param x the x-coordinate the touch event */ protected void updateVerticalPanelPosition(float x) { - if (mNotificationStackScroller.getWidth() * 1.75f > mView.getWidth()) { + if (mNotificationStackScrollLayoutController.getWidth() * 1.75f > mView.getWidth()) { resetHorizontalPanelPosition(); return; } - float leftMost = mPositionMinSideMargin + mNotificationStackScroller.getWidth() / 2; + float leftMost = mPositionMinSideMargin + + mNotificationStackScrollLayoutController.getWidth() / 2; float rightMost = mView.getWidth() - mPositionMinSideMargin - - mNotificationStackScroller.getWidth() / 2; - if (Math.abs(x - mView.getWidth() / 2) < mNotificationStackScroller.getWidth() / 4) { + - mNotificationStackScrollLayoutController.getWidth() / 2; + if (Math.abs(x - mView.getWidth() / 2) + < mNotificationStackScrollLayoutController.getWidth() / 4) { x = mView.getWidth() / 2; } x = Math.min(rightMost, Math.max(leftMost, x)); float - center = - mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2; + center = mNotificationStackScrollLayoutController.getLeft() + + mNotificationStackScrollLayoutController.getWidth() / 2; setHorizontalPanelTranslation(x - center); } @@ -2659,7 +2699,7 @@ public class NotificationPanelViewController extends PanelViewController { } protected void setHorizontalPanelTranslation(float translation) { - mNotificationStackScroller.setTranslationX(translation); + mNotificationStackScrollLayoutController.setTranslationX(translation); mQsFrame.setTranslationX(translation); int size = mVerticalTranslationListener.size(); for (int i = 0; i < size; i++) { @@ -2669,13 +2709,14 @@ public class NotificationPanelViewController extends PanelViewController { protected void updateExpandedHeight(float expandedHeight) { if (mTracking) { - mNotificationStackScroller.setExpandingVelocity(getCurrentExpandVelocity()); + mNotificationStackScrollLayoutController + .setExpandingVelocity(getCurrentExpandVelocity()); } if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) { // The expandedHeight is always the full panel Height when bypassing expandedHeight = getMaxPanelHeightNonBypass(); } - mNotificationStackScroller.setExpandedHeight(expandedHeight); + mNotificationStackScrollLayoutController.setExpandedHeight(expandedHeight); updateKeyguardBottomAreaAlpha(); updateBigClockAlpha(); updateStatusBarIcons(); @@ -2835,7 +2876,7 @@ public class NotificationPanelViewController extends PanelViewController { mHeightListener.onQsHeightChanged(); } }); - mNotificationStackScroller.setQsContainer((ViewGroup) mQs.getView()); + mNotificationStackScrollLayoutController.setQsContainer((ViewGroup) mQs.getView()); if (mQs instanceof QSFragment) { mKeyguardStatusBar.setQSPanel(((QSFragment) mQs).getQsPanel()); } @@ -2859,7 +2900,7 @@ public class NotificationPanelViewController extends PanelViewController { if (disabled && mAffordanceHelper.isSwipingInProgress() && !mIsLaunchTransitionRunning) { mAffordanceHelper.reset(false /* animate */); } - mNotificationStackScroller.setAnimationsEnabled(!disabled); + mNotificationStackScrollLayoutController.setAnimationsEnabled(!disabled); } /** @@ -2873,7 +2914,7 @@ public class NotificationPanelViewController extends PanelViewController { if (dozing == mDozing) return; mView.setDozing(dozing); mDozing = dozing; - mNotificationStackScroller.setDozing(mDozing, animate, wakeUpTouchLocation); + mNotificationStackScrollLayoutController.setDozing(mDozing, animate, wakeUpTouchLocation); mKeyguardBottomArea.setDozing(mDozing, animate); if (dozing) { @@ -2901,7 +2942,7 @@ public class NotificationPanelViewController extends PanelViewController { if (!mPulsing && !mDozing) { mAnimateNextPositionUpdate = false; } - mNotificationStackScroller.setPulsing(pulsing, animatePulse); + mNotificationStackScrollLayoutController.setPulsing(pulsing, animatePulse); mKeyguardStatusView.setPulsing(pulsing); } @@ -3006,7 +3047,7 @@ public class NotificationPanelViewController extends PanelViewController { } public boolean hasActiveClearableNotifications() { - return mNotificationStackScroller.hasActiveClearableNotifications(ROWS_ALL); + return mNotificationStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL); } private void updateShowEmptyShadeView() { @@ -3017,54 +3058,57 @@ public class NotificationPanelViewController extends PanelViewController { } public RemoteInputController.Delegate createRemoteInputDelegate() { - return mNotificationStackScroller.createDelegate(); + return mNotificationStackScrollLayoutController.createDelegate(); } void updateNotificationViews(String reason) { - mNotificationStackScroller.updateSectionBoundaries(reason); - mNotificationStackScroller.updateSpeedBumpIndex(); - mNotificationStackScroller.updateFooter(); + mNotificationStackScrollLayoutController.updateSectionBoundaries(reason); + mNotificationStackScrollLayoutController.updateSpeedBumpIndex(); + mNotificationStackScrollLayoutController.updateFooter(); updateShowEmptyShadeView(); - mNotificationStackScroller.updateIconAreaViews(); + mNotificationStackScrollLayoutController.updateIconAreaViews(); } public void onUpdateRowStates() { - mNotificationStackScroller.onUpdateRowStates(); + mNotificationStackScrollLayoutController.onUpdateRowStates(); } public boolean hasPulsingNotifications() { - return mNotificationStackScroller.hasPulsingNotifications(); + return mNotificationStackScrollLayoutController + .getNotificationListContainer().hasPulsingNotifications(); } public ActivatableNotificationView getActivatedChild() { - return mNotificationStackScroller.getActivatedChild(); + return mNotificationStackScrollLayoutController.getActivatedChild(); } public void setActivatedChild(ActivatableNotificationView o) { - mNotificationStackScroller.setActivatedChild(o); + mNotificationStackScrollLayoutController.setActivatedChild(o); } public void runAfterAnimationFinished(Runnable r) { - mNotificationStackScroller.runAfterAnimationFinished(r); + mNotificationStackScrollLayoutController.runAfterAnimationFinished(r); } public void setScrollingEnabled(boolean b) { - mNotificationStackScroller.setScrollingEnabled(b); + mNotificationStackScrollLayoutController.setScrollingEnabled(b); } public void initDependencies(StatusBar statusBar, NotificationGroupManager groupManager, - NotificationShelf notificationShelf, + NotificationShelfController notificationShelfController, NotificationIconAreaController notificationIconAreaController, ScrimController scrimController) { setStatusBar(statusBar); setGroupManager(mGroupManager); - mNotificationStackScroller.setNotificationPanelController(this); - mNotificationStackScroller.setIconAreaController(notificationIconAreaController); - mNotificationStackScroller.setStatusBar(statusBar); - mNotificationStackScroller.setGroupManager(groupManager); - mNotificationStackScroller.setShelf(notificationShelf); - mNotificationStackScroller.setScrimController(scrimController); + mNotificationStackScrollLayoutController.setNotificationPanelController(this); + mNotificationStackScrollLayoutController + .setIconAreaController(notificationIconAreaController); + mNotificationStackScrollLayoutController.setStatusBar(statusBar); + mNotificationStackScrollLayoutController.setGroupManager(groupManager); + mNotificationStackScrollLayoutController.setShelfController(notificationShelfController); + mNotificationStackScrollLayoutController.setScrimController(scrimController); updateShowEmptyShadeView(); + mNotificationShelfController = notificationShelfController; } public void showTransientIndication(int id) { @@ -3216,6 +3260,10 @@ public class NotificationPanelViewController extends PanelViewController { return new OnConfigurationChangedListener(); } + public NotificationStackScrollLayoutController getNotificationStackScrollLayoutController() { + return mNotificationStackScrollLayoutController; + } + private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener { @Override public void onHeightChanged(ExpandableView view, boolean needsAnimation) { @@ -3228,7 +3276,8 @@ public class NotificationPanelViewController extends PanelViewController { if (needsAnimation && mInterpolatedDarkAmount == 0) { mAnimateNextPositionUpdate = true; } - ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone(); + ExpandableView firstChildNotGone = + mNotificationStackScrollLayoutController.getFirstChildNotGone(); ExpandableNotificationRow firstRow = firstChildNotGone instanceof ExpandableNotificationRow @@ -3454,13 +3503,13 @@ public class NotificationPanelViewController extends PanelViewController { private class MyOnHeadsUpChangedListener implements OnHeadsUpChangedListener { @Override public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) { - mNotificationStackScroller.setInHeadsUpPinnedMode(inPinnedMode); + mNotificationStackScrollLayoutController.setInHeadsUpPinnedMode(inPinnedMode); if (inPinnedMode) { mHeadsUpExistenceChangedRunnable.run(); updateNotificationTranslucency(); } else { setHeadsUpAnimatingAway(true); - mNotificationStackScroller.runAfterAnimationFinished( + mNotificationStackScrollLayoutController.runAfterAnimationFinished( mHeadsUpExistenceChangedRunnable); } updateGestureExclusionRect(); @@ -3472,8 +3521,8 @@ public class NotificationPanelViewController extends PanelViewController { @Override public void onHeadsUpPinned(NotificationEntry entry) { if (!isOnKeyguard()) { - mNotificationStackScroller.generateHeadsUpAnimation(entry.getHeadsUpAnimationView(), - true); + mNotificationStackScrollLayoutController.generateHeadsUpAnimation( + entry.getHeadsUpAnimationView(), true); } } @@ -3485,7 +3534,7 @@ public class NotificationPanelViewController extends PanelViewController { // notification // will stick to the top without any interaction. if (isFullyCollapsed() && entry.isRowHeadsUp() && !isOnKeyguard()) { - mNotificationStackScroller.generateHeadsUpAnimation( + mNotificationStackScrollLayoutController.generateHeadsUpAnimation( entry.getHeadsUpAnimationView(), false); entry.setHeadsUpIsVisible(); } @@ -3493,7 +3542,7 @@ public class NotificationPanelViewController extends PanelViewController { @Override public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { - mNotificationStackScroller.generateHeadsUpAnimation(entry, isHeadsUp); + mNotificationStackScrollLayoutController.generateHeadsUpAnimation(entry, isHeadsUp); } } @@ -3508,7 +3557,7 @@ public class NotificationPanelViewController extends PanelViewController { if (mAccessibilityManager.isEnabled()) { mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle()); } - mNotificationStackScroller.setMaxTopPadding( + mNotificationStackScrollLayoutController.setMaxTopPadding( mQsMaxExpansionHeight + mQsNotificationTopPadding); } } @@ -3570,7 +3619,7 @@ public class NotificationPanelViewController extends PanelViewController { } else if (oldState == StatusBarState.SHADE_LOCKED && statusBarState == StatusBarState.KEYGUARD) { animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD); - mNotificationStackScroller.resetScrollPosition(); + mNotificationStackScrollLayoutController.resetScrollPosition(); // Only animate header if the header is visible. If not, it will partially // animate out // the top of QS @@ -3646,7 +3695,7 @@ public class NotificationPanelViewController extends PanelViewController { int oldTop, int oldRight, int oldBottom) { DejankUtils.startDetectingBlockingIpcs("NVP#onLayout"); super.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom); - setIsFullWidth(mNotificationStackScroller.getWidth() == mView.getWidth()); + setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth()); // Update Clock Pivot mKeyguardStatusView.setPivotX(mView.getWidth() / 2); @@ -3662,7 +3711,7 @@ public class NotificationPanelViewController extends PanelViewController { mQsExpansionHeight = mQsMinExpansionHeight; } mQsMaxExpansionHeight = mQs.getDesiredHeight(); - mNotificationStackScroller.setMaxTopPadding( + mNotificationStackScrollLayoutController.setMaxTopPadding( mQsMaxExpansionHeight + mQsNotificationTopPadding); } positionClockAndNotifications(); @@ -3724,7 +3773,7 @@ public class NotificationPanelViewController extends PanelViewController { 0, calculateQsTopPadding(), mView.getWidth(), calculateQsTopPadding(), p); p.setColor(Color.CYAN); canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, mView.getWidth(), - mNotificationStackScroller.getTopPadding(), p); + mNotificationStackScrollLayoutController.getTopPadding(), p); p.setColor(Color.GRAY); canvas.drawLine(0, mClockPositionResult.clockY, mView.getWidth(), mClockPositionResult.clockY, p); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 8cb54eef01b4..e42c3dc4f589 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -284,13 +284,22 @@ public class PhoneStatusBarPolicy mResources.getString(R.string.accessibility_data_saver_on)); mIconController.setIconVisibility(mSlotDataSaver, false); + // privacy items + String microphoneString = mResources.getString(PrivacyType.TYPE_MICROPHONE.getNameId()); + String microphoneDesc = mResources.getString( + R.string.ongoing_privacy_chip_content_multiple_apps, microphoneString); mIconController.setIcon(mSlotMicrophone, PrivacyType.TYPE_MICROPHONE.getIconId(), - mResources.getString(PrivacyType.TYPE_MICROPHONE.getNameId())); + microphoneDesc); mIconController.setIconVisibility(mSlotMicrophone, false); + + String cameraString = mResources.getString(PrivacyType.TYPE_CAMERA.getNameId()); + String cameraDesc = mResources.getString( + R.string.ongoing_privacy_chip_content_multiple_apps, cameraString); mIconController.setIcon(mSlotCamera, PrivacyType.TYPE_CAMERA.getIconId(), - mResources.getString(PrivacyType.TYPE_CAMERA.getNameId())); + cameraDesc); mIconController.setIconVisibility(mSlotCamera, false); + mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID, mResources.getString(R.string.accessibility_location_active)); mIconController.setIconVisibility(mSlotLocation, false); 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 eb626280b494..aa8985f43be0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -179,7 +179,6 @@ import com.android.systemui.statusbar.AutoHideUiElement; import com.android.systemui.statusbar.BackDropView; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CrossFadeHelper; -import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.GestureRecorder; import com.android.systemui.statusbar.KeyboardShortcuts; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -189,7 +188,7 @@ import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShadeDepthController; -import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.ScrimView; @@ -210,6 +209,8 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule; import com.android.systemui.statusbar.policy.BatteryController; @@ -646,6 +647,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final BubbleController.BubbleExpandListener mBubbleExpandListener; private ActivityIntentHelper mActivityIntentHelper; + private NotificationStackScrollLayoutController mStackScrollerController; /** * Public constructor for StatusBar. @@ -1016,9 +1018,11 @@ public class StatusBar extends SystemUI implements DemoMode, // TODO: Deal with the ugliness that comes from having some of the statusbar broken out // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot. - mStackScroller = mNotificationShadeWindowView.findViewById( - R.id.notification_stack_scroller); - NotificationListContainer notifListContainer = (NotificationListContainer) mStackScroller; + mStackScrollerController = + mNotificationPanelViewController.getNotificationStackScrollLayoutController(); + mStackScroller = mStackScrollerController.getView(); + NotificationListContainer notifListContainer = + mStackScrollerController.getNotificationListContainer(); mNotificationLogger.setUpWithContainer(notifListContainer); // TODO: make this injectable. Currently that would create a circular dependency between @@ -1029,7 +1033,7 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarStateController); mWakeUpCoordinator.setIconAreaController(mNotificationIconAreaController); inflateShelf(); - mNotificationIconAreaController.setupShelf(mNotificationShelf); + mNotificationIconAreaController.setupShelf(mNotificationShelfController); mNotificationPanelViewController.setOnReinflationListener( mNotificationIconAreaController::initAodIcons); mNotificationPanelViewController.addExpansionListener(mWakeUpCoordinator); @@ -1076,7 +1080,7 @@ public class StatusBar extends SystemUI implements DemoMode, // TODO (b/136993073) Separate notification shade and status bar mHeadsUpAppearanceController = new HeadsUpAppearanceController( mNotificationIconAreaController, mHeadsUpManager, - mNotificationShadeWindowView, + mStackScroller.getController(), mStatusBarStateController, mKeyguardBypassController, mKeyguardStateController, mWakeUpCoordinator, mCommandQueue, mNotificationPanelViewController, mStatusBarView); @@ -1147,7 +1151,8 @@ public class StatusBar extends SystemUI implements DemoMode, }); mScrimController.attachViews(scrimBehind, scrimInFront, scrimForBubble); - mNotificationPanelViewController.initDependencies(this, mGroupManager, mNotificationShelf, + mNotificationPanelViewController.initDependencies(this, mGroupManager, + mNotificationShelfController, mNotificationIconAreaController, mScrimController); BackDropView backdrop = mNotificationShadeWindowView.findViewById(R.id.backdrop); @@ -1300,17 +1305,19 @@ public class StatusBar extends SystemUI implements DemoMode, mActivityLaunchAnimator = new ActivityLaunchAnimator( mNotificationShadeWindowViewController, this, mNotificationPanelViewController, mNotificationShadeDepthControllerLazy.get(), - (NotificationListContainer) mStackScroller, mContext.getMainExecutor()); + mStackScrollerController.getNotificationListContainer(), + mContext.getMainExecutor()); // TODO: inject this. mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController, - mHeadsUpManager, mNotificationShadeWindowView, mStackScroller, mDozeScrimController, - mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController, - mKeyguardStateController, mKeyguardIndicationController, + mHeadsUpManager, mNotificationShadeWindowView, mStackScrollerController, + mDozeScrimController, mScrimController, mActivityLaunchAnimator, + mDynamicPrivacyController, mKeyguardStateController, + mKeyguardIndicationController, this /* statusBar */, mShadeController, mCommandQueue, mInitController, mNotificationInterruptStateProvider); - mNotificationShelf.setOnActivatedListener(mPresenter); + mNotificationShelfController.setOnActivatedListener(mPresenter); mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController); mNotificationActivityStarter = @@ -1320,16 +1327,13 @@ public class StatusBar extends SystemUI implements DemoMode, .setNotificationPresenter(mPresenter) .setNotificationPanelViewController(mNotificationPanelViewController) .build(); - - ((NotificationListContainer) mStackScroller) - .setNotificationActivityStarter(mNotificationActivityStarter); - + mStackScroller.setNotificationActivityStarter(mNotificationActivityStarter); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); mNotificationsController.initialize( this, mPresenter, - (NotificationListContainer) mStackScroller, + mStackScrollerController.getNotificationListContainer(), mNotificationActivityStarter, mPresenter); } @@ -1386,8 +1390,9 @@ public class StatusBar extends SystemUI implements DemoMode, } private void inflateShelf() { - mNotificationShelf = mSuperStatusBarViewFactory.getNotificationShelf(mStackScroller); - mNotificationShelf.setOnClickListener(mGoToLockedShadeListener); + mNotificationShelfController = mSuperStatusBarViewFactory + .getNotificationShelfController(mStackScroller); + mNotificationShelfController.setOnClickListener(mGoToLockedShadeListener); } @Override @@ -4049,7 +4054,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected IStatusBarService mBarService; // all notifications - protected ViewGroup mStackScroller; + protected NotificationStackScrollLayout mStackScroller; private final NotificationGroupManager mGroupManager; @@ -4085,8 +4090,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final Optional<Recents> mRecentsOptional; - protected NotificationShelf mNotificationShelf; - protected EmptyShadeView mEmptyShadeView; + protected NotificationShelfController mNotificationShelfController; private final Lazy<AssistManager> mAssistManagerLazy; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 45f0c49a4fd4..f1715bef62d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -30,7 +30,6 @@ import android.service.vr.IVrStateCallbacks; import android.util.Log; import android.util.Slog; import android.view.View; -import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager; import android.widget.TextView; @@ -71,7 +70,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener; -import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -133,7 +132,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, NotificationPanelViewController panel, HeadsUpManagerPhone headsUp, NotificationShadeWindowView statusBarWindow, - ViewGroup stackScroller, + NotificationStackScrollLayoutController stackScrollerController, DozeScrimController dozeScrimController, ScrimController scrimController, ActivityLaunchAnimator activityLaunchAnimator, @@ -155,7 +154,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mStatusBar = statusBar; mShadeController = shadeController; mCommandQueue = commandQueue; - mAboveShelfObserver = new AboveShelfObserver(stackScroller); + mAboveShelfObserver = new AboveShelfObserver(stackScrollerController.getView()); mActivityLaunchAnimator = activityLaunchAnimator; mAboveShelfObserver.setListener(statusBarWindow.findViewById( R.id.notification_container_parent)); @@ -190,7 +189,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, remoteInputManager.getController().addCallback( Dependency.get(NotificationShadeWindowController.class)); - NotificationListContainer notifListContainer = (NotificationListContainer) stackScroller; initController.addPostInitTask(() -> { NotificationEntryListener notificationEntryListener = new NotificationEntryListener() { @Override @@ -207,7 +205,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } }; - mViewHierarchyManager.setUpWithPresenter(this, notifListContainer); + mViewHierarchyManager.setUpWithPresenter(this, + stackScrollerController.getNotificationListContainer()); mEntryManager.setUpWithPresenter(this); mEntryManager.addNotificationEntryListener(notificationEntryListener); mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager); @@ -219,7 +218,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mMediaManager.setUpWithPresenter(this); mVisualStabilityManager.setUpWithPresenter(this); mGutsManager.setUpWithPresenter(this, - notifListContainer, mCheckSaveListener, mOnSettingsClickListener); + stackScrollerController.getNotificationListContainer(), mCheckSaveListener, + mOnSettingsClickListener); // ForegroundServiceNotificationListener adds its listener in its constructor // but we need to request it here in order for it to be instantiated. // TODO: figure out how to do this correctly once Dependency.get() is gone. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java index 72395e68ff07..ac69d9c32c93 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java @@ -244,9 +244,10 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, @Override public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent, + boolean appRequestedAuth, NotificationRemoteInputManager.ClickHandler defaultHandler) { final boolean isActivity = pendingIntent.isActivity(); - if (isActivity) { + if (isActivity || appRequestedAuth) { mActionClickLogger.logWaitingToCloseKeyguard(pendingIntent); final boolean afterKeyguardGone = mActivityIntentHelper.wouldLaunchResolverActivity( pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java index 87b3956060f3..bbab6253a4d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java @@ -40,5 +40,9 @@ abstract class AudioActivityObserver { mListener = listener; } + abstract void start(); + + abstract void stop(); + abstract Set<String> getActivePackages(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java index 8e4e12358836..e3eed35f0483 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java @@ -22,12 +22,12 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; import android.annotation.IntDef; import android.annotation.UiThread; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.database.ContentObserver; import android.graphics.PixelFormat; import android.provider.Settings; import android.text.TextUtils; @@ -65,11 +65,13 @@ public class AudioRecordingDisclosureBar implements // CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest private static final String LAYOUT_PARAMS_TITLE = "MicrophoneCaptureIndicator"; + private static final String ENABLE_FLAG = "sysui_mic_disclosure_enable"; private static final String EXEMPT_PACKAGES_LIST = "sysui_mic_disclosure_exempt"; private static final String FORCED_PACKAGES_LIST = "sysui_mic_disclosure_forced"; @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"STATE_"}, value = { + STATE_STOPPED, STATE_NOT_SHOWN, STATE_APPEARING, STATE_SHOWN, @@ -80,6 +82,7 @@ public class AudioRecordingDisclosureBar implements }) public @interface State {} + private static final int STATE_STOPPED = -1; private static final int STATE_NOT_SHOWN = 0; private static final int STATE_APPEARING = 1; private static final int STATE_SHOWN = 2; @@ -90,10 +93,9 @@ public class AudioRecordingDisclosureBar implements private static final int ANIMATION_DURATION = 600; private static final int MAXIMIZED_DURATION = 3000; - private static final int PULSE_BIT_DURATION = 1000; - private static final float PULSE_SCALE = 1.25f; private final Context mContext; + private boolean mIsEnabledInSettings; private View mIndicatorView; private View mIconTextsContainer; @@ -104,13 +106,13 @@ public class AudioRecordingDisclosureBar implements private TextView mTextView; private boolean mIsLtr; - @State private int mState = STATE_NOT_SHOWN; + @State private int mState = STATE_STOPPED; /** * Array of the observers that monitor different aspects of the system, such as AppOps and * microphone foreground services */ - private final AudioActivityObserver[] mAudioActivityObservers; + private AudioActivityObserver[] mAudioActivityObservers; /** * Whether the indicator should expand and show the recording application's label. * If disabled ({@code false}) the "minimized" ({@link #STATE_MINIMIZED}) indicator would appear @@ -144,6 +146,7 @@ public class AudioRecordingDisclosureBar implements public AudioRecordingDisclosureBar(Context context) { mContext = context; + // Loading configs mRevealRecordingPackages = mContext.getResources().getBoolean( R.bool.audio_recording_disclosure_reveal_packages); mExemptPackages = new ArraySet<>( @@ -152,10 +155,52 @@ public class AudioRecordingDisclosureBar implements mExemptPackages.addAll(Arrays.asList(getGlobalStringArray(EXEMPT_PACKAGES_LIST))); mExemptPackages.removeAll(Arrays.asList(getGlobalStringArray(FORCED_PACKAGES_LIST))); - mAudioActivityObservers = new AudioActivityObserver[]{ - new RecordAudioAppOpObserver(mContext, this), - new MicrophoneForegroundServicesObserver(mContext, this), - }; + // Check setting, and start if enabled + mIsEnabledInSettings = checkIfEnabledInSettings(); + registerSettingsObserver(); + if (mIsEnabledInSettings) { + start(); + } + } + + @UiThread + private void start() { + if (mState != STATE_STOPPED) { + return; + } + mState = STATE_NOT_SHOWN; + + if (mAudioActivityObservers == null) { + mAudioActivityObservers = new AudioActivityObserver[]{ + new RecordAudioAppOpObserver(mContext, this), + new MicrophoneForegroundServicesObserver(mContext, this), + }; + } + + for (int i = mAudioActivityObservers.length - 1; i >= 0; i--) { + mAudioActivityObservers[i].start(); + } + } + + @UiThread + private void stop() { + if (mState == STATE_STOPPED) { + return; + } + mState = STATE_STOPPED; + + for (int i = mAudioActivityObservers.length - 1; i >= 0; i--) { + mAudioActivityObservers[i].stop(); + } + + // Remove the view if shown. + if (mState != STATE_NOT_SHOWN) { + removeIndicatorView(); + } + + // Clean up the state. + mSessionNotifiedPackages.clear(); + mPendingNotificationPackages.clear(); } @UiThread @@ -213,7 +258,6 @@ public class AudioRecordingDisclosureBar implements @UiThread private void hideIndicatorIfNeeded() { - if (DEBUG) Log.d(TAG, "hideIndicatorIfNeeded"); // If not MINIMIZED, will check whether the indicator should be hidden when the indicator // comes to the STATE_MINIMIZED eventually. if (mState != STATE_MINIMIZED) return; @@ -222,7 +266,6 @@ public class AudioRecordingDisclosureBar implements for (int index = mAudioActivityObservers.length - 1; index >= 0; index--) { for (String activePackage : mAudioActivityObservers[index].getActivePackages()) { if (mExemptPackages.contains(activePackage)) continue; - if (DEBUG) Log.d(TAG, " - there are still ongoing activities"); return; } } @@ -235,7 +278,7 @@ public class AudioRecordingDisclosureBar implements @UiThread private void show(String packageName) { if (DEBUG) { - Log.d(TAG, "Showing indicator for " + packageName); + Log.d(TAG, "Showing indicator"); } mIsLtr = mContext.getResources().getConfiguration().getLayoutDirection() @@ -286,6 +329,10 @@ public class AudioRecordingDisclosureBar implements new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { + if (mState == STATE_STOPPED) { + return; + } + // Remove the observer mIndicatorView.getViewTreeObserver().removeOnGlobalLayoutListener( this); @@ -306,13 +353,16 @@ public class AudioRecordingDisclosureBar implements @Override public void onAnimationStart(Animator animation, boolean isReverse) { + if (mState == STATE_STOPPED) { + return; + } + // Indicator is INVISIBLE at the moment, change it. mIndicatorView.setVisibility(View.VISIBLE); } @Override public void onAnimationEnd(Animator animation) { - startPulsatingAnimation(); if (mRevealRecordingPackages) { onExpanded(); } else { @@ -345,9 +395,6 @@ public class AudioRecordingDisclosureBar implements assertRevealingRecordingPackages(); final String label = getApplicationLabel(packageName); - if (DEBUG) { - Log.d(TAG, "Expanding for " + packageName + " (" + label + ")..."); - } mTextView.setText(mContext.getString(R.string.app_accessed_mic, label)); final AnimatorSet set = new AnimatorSet(); @@ -373,7 +420,6 @@ public class AudioRecordingDisclosureBar implements private void minimize() { assertRevealingRecordingPackages(); - if (DEBUG) Log.d(TAG, "Minimizing..."); final int targetOffset = (mIsLtr ? 1 : -1) * mTextsContainers.getWidth(); final AnimatorSet set = new AnimatorSet(); set.playTogether( @@ -396,7 +442,9 @@ public class AudioRecordingDisclosureBar implements @UiThread private void hide() { - if (DEBUG) Log.d(TAG, "Hiding..."); + if (DEBUG) { + Log.d(TAG, "Hide indicator"); + } final int targetOffset = (mIsLtr ? 1 : -1) * (mIndicatorView.getWidth() - (int) mIconTextsContainer.getTranslationX()); final AnimatorSet set = new AnimatorSet(); @@ -418,9 +466,12 @@ public class AudioRecordingDisclosureBar implements @UiThread private void onExpanded() { + if (mState == STATE_STOPPED) { + return; + } + assertRevealingRecordingPackages(); - if (DEBUG) Log.d(TAG, "Expanded"); mState = STATE_SHOWN; mIndicatorView.postDelayed(this::minimize, MAXIMIZED_DURATION); @@ -428,7 +479,10 @@ public class AudioRecordingDisclosureBar implements @UiThread private void onMinimized() { - if (DEBUG) Log.d(TAG, "Minimized"); + if (mState == STATE_STOPPED) { + return; + } + mState = STATE_MINIMIZED; if (mRevealRecordingPackages) { @@ -443,8 +497,21 @@ public class AudioRecordingDisclosureBar implements @UiThread private void onHidden() { - if (DEBUG) Log.d(TAG, "Hidden"); + if (mState == STATE_STOPPED) { + return; + } + removeIndicatorView(); + mState = STATE_NOT_SHOWN; + + // Check if anybody started recording while we were in STATE_DISAPPEARING + if (!mPendingNotificationPackages.isEmpty()) { + // There is a new application that started recording, tell the user about it. + show(mPendingNotificationPackages.poll()); + } + } + + private void removeIndicatorView() { final WindowManager windowManager = (WindowManager) mContext.getSystemService( Context.WINDOW_SERVICE); windowManager.removeView(mIndicatorView); @@ -456,28 +523,6 @@ public class AudioRecordingDisclosureBar implements mTextsContainers = null; mTextView = null; mBgEnd = null; - - mState = STATE_NOT_SHOWN; - - // Check if anybody started recording while we were in STATE_DISAPPEARING - if (!mPendingNotificationPackages.isEmpty()) { - // There is a new application that started recording, tell the user about it. - show(mPendingNotificationPackages.poll()); - } - } - - @UiThread - private void startPulsatingAnimation() { - final View pulsatingView = mIconTextsContainer.findViewById(R.id.pulsating_circle); - final ObjectAnimator animator = - ObjectAnimator.ofPropertyValuesHolder( - pulsatingView, - PropertyValuesHolder.ofFloat(View.SCALE_X, PULSE_SCALE), - PropertyValuesHolder.ofFloat(View.SCALE_Y, PULSE_SCALE)); - animator.setDuration(PULSE_BIT_DURATION); - animator.setRepeatCount(ObjectAnimator.INFINITE); - animator.setRepeatMode(ObjectAnimator.REVERSE); - animator.start(); } private String[] getGlobalStringArray(String setting) { @@ -504,4 +549,33 @@ public class AudioRecordingDisclosureBar implements DEBUG ? new RuntimeException("Should not be called") : null); } } + + private boolean checkIfEnabledInSettings() { + // 0 = disabled, everything else = enabled. Enabled by default. + return Settings.Global.getInt(mContext.getContentResolver(), + ENABLE_FLAG, 1) != 0; + } + + private void registerSettingsObserver() { + final ContentObserver contentObserver = new ContentObserver( + mContext.getMainThreadHandler()) { + @Override + public void onChange(boolean selfChange) { + if (mIsEnabledInSettings == checkIfEnabledInSettings()) { + // Nothing changed as we know it - ignore. + return; + } + + // Things changed: flip the flag. + mIsEnabledInSettings = !mIsEnabledInSettings; + if (mIsEnabledInSettings) { + start(); + } else { + stop(); + } + } + }; + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(ENABLE_FLAG), false, contentObserver); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java index 1ede88a26020..8caf95fb48f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java @@ -30,7 +30,6 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -41,9 +40,8 @@ import java.util.Set; */ class MicrophoneForegroundServicesObserver extends AudioActivityObserver { private static final String TAG = "MicrophoneForegroundServicesObserver"; - private static final boolean ENABLED = true; - private final IActivityManager mActivityManager; + private IActivityManager mActivityManager; /** * A dictionary that maps PIDs to the package names. We only keep track of the PIDs that are * "active" (those that are running FGS with FOREGROUND_SERVICE_TYPE_MICROPHONE flag). @@ -60,7 +58,10 @@ class MicrophoneForegroundServicesObserver extends AudioActivityObserver { MicrophoneForegroundServicesObserver(Context context, OnAudioActivityStateChangeListener listener) { super(context, listener); + } + @Override + void start() { mActivityManager = ActivityManager.getService(); try { mActivityManager.registerProcessObserver(mProcessObserver); @@ -70,8 +71,19 @@ class MicrophoneForegroundServicesObserver extends AudioActivityObserver { } @Override + void stop() { + try { + mActivityManager.unregisterProcessObserver(mProcessObserver); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't unregister process observer", e); + } + mActivityManager = null; + mPackageToProcessCount.clear(); + } + + @Override Set<String> getActivePackages() { - return ENABLED ? mPackageToProcessCount.keySet() : Collections.emptySet(); + return mPackageToProcessCount.keySet(); } @UiThread @@ -141,13 +153,12 @@ class MicrophoneForegroundServicesObserver extends AudioActivityObserver { @UiThread private void notifyPackageStateChanged(String packageName, boolean active) { - if (active) { - if (DEBUG) Log.d(TAG, "New microphone fgs detected, package=" + packageName); - } else { - if (DEBUG) Log.d(TAG, "Microphone fgs is gone, package=" + packageName); + if (DEBUG) { + Log.d(TAG, (active ? "New microphone fgs detected" : "Microphone fgs is gone") + + ", package=" + packageName); } - if (ENABLED) mListener.onAudioActivityStateChange(active, packageName); + mListener.onAudioActivityStateChange(active, packageName); } @UiThread diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java index b5b1c2b3018a..9a2b4a93ac89 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java @@ -42,14 +42,33 @@ class RecordAudioAppOpObserver extends AudioActivityObserver implements RecordAudioAppOpObserver(Context context, OnAudioActivityStateChangeListener listener) { super(context, listener); + } + + @Override + void start() { + if (DEBUG) { + Log.d(TAG, "Start"); + } // Register AppOpsManager callback - final AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService( - Context.APP_OPS_SERVICE); - appOpsManager.startWatchingActive( - new String[]{AppOpsManager.OPSTR_RECORD_AUDIO}, - mContext.getMainExecutor(), - this); + mContext.getSystemService(AppOpsManager.class) + .startWatchingActive( + new String[]{AppOpsManager.OPSTR_RECORD_AUDIO}, + mContext.getMainExecutor(), + this); + } + + @Override + void stop() { + if (DEBUG) { + Log.d(TAG, "Stop"); + } + + // Unregister AppOpsManager callback + mContext.getSystemService(AppOpsManager.class).stopWatchingActive(this); + + // Clean up state + mActiveAudioRecordingPackages.clear(); } @UiThread diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java index dce38c109930..fd6ba1a6af0e 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java @@ -19,11 +19,10 @@ package com.android.systemui.tv; import com.android.systemui.dagger.DefaultComponentBinder; import com.android.systemui.dagger.DependencyBinder; import com.android.systemui.dagger.DependencyProvider; +import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.SystemServicesModule; import com.android.systemui.dagger.SystemUIBinder; -import com.android.systemui.dagger.SystemUIDefaultModule; import com.android.systemui.dagger.SystemUIModule; -import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.onehanded.dagger.OneHandedModule; import javax.inject.Singleton; @@ -42,14 +41,17 @@ import dagger.Component; SystemServicesModule.class, SystemUIBinder.class, SystemUIModule.class, - SystemUIDefaultModule.class, + TvSystemUIModule.class, TvSystemUIBinder.class}) -public interface TvSystemUIRootComponent extends SystemUIRootComponent { +public interface TvGlobalRootComponent extends GlobalRootComponent { /** * Component Builder interface. This allows to bind Context instance in the component */ @Component.Builder - interface Builder extends SystemUIRootComponent.Builder { - TvSystemUIRootComponent build(); + interface Builder extends GlobalRootComponent.Builder { + TvGlobalRootComponent build(); } + + @Override + TvSysUIComponent.Builder getSysUIComponent(); } diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java new file mode 100644 index 000000000000..bc0cb51c64a3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.tv; + +import com.android.systemui.dagger.SysUIComponent; +import com.android.systemui.dagger.SysUISingleton; + +import dagger.Subcomponent; + +/** + * Dagger Subcomponent for Core SysUI. + */ +@SysUISingleton +@Subcomponent(modules = {}) +public interface TvSysUIComponent extends SysUIComponent { + + /** + * Builder for a SysUIComponent. + */ + @Subcomponent.Builder + interface Builder extends SysUIComponent.Builder { + TvSysUIComponent build(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java index be30a4a4c72e..9a44bf12a3ef 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java @@ -16,7 +16,7 @@ package com.android.systemui.tv; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.pip.tv.dagger.PipModule; import dagger.Binds; @@ -25,5 +25,5 @@ import dagger.Module; @Module(includes = {PipModule.class}) interface TvSystemUIBinder { @Binds - SystemUIRootComponent bindSystemUIRootComponent(TvSystemUIRootComponent systemUIRootComponent); + GlobalRootComponent bindGlobalRootComponent(TvGlobalRootComponent globalRootComponent); } diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java index 7d3ec678fd5f..c99ad23ab23d 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java @@ -19,16 +19,16 @@ package com.android.systemui.tv; import android.content.Context; import com.android.systemui.SystemUIFactory; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; /** - * TV variant {@link SystemUIFactory}, that substitutes default {@link SystemUIRootComponent} for - * {@link TvSystemUIRootComponent} + * TV variant {@link SystemUIFactory}, that substitutes default {@link GlobalRootComponent} for + * {@link TvGlobalRootComponent} */ public class TvSystemUIFactory extends SystemUIFactory { @Override - protected SystemUIRootComponent buildSystemUIRootComponent(Context context) { - return DaggerTvSystemUIRootComponent.builder() + protected GlobalRootComponent buildGlobalRootComponent(Context context) { + return DaggerTvGlobalRootComponent.builder() .context(context) .build(); } diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java new file mode 100644 index 000000000000..3f7350639fd3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.tv; + +import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; +import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME; + +import android.content.Context; +import android.os.Handler; +import android.os.PowerManager; + +import androidx.annotation.Nullable; + +import com.android.keyguard.KeyguardViewController; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.dock.DockManager; +import com.android.systemui.dock.DockManagerImpl; +import com.android.systemui.doze.DozeHost; +import com.android.systemui.plugins.qs.QSFactory; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.power.EnhancedEstimates; +import com.android.systemui.power.EnhancedEstimatesImpl; +import com.android.systemui.qs.dagger.QSModule; +import com.android.systemui.qs.tileimpl.QSFactoryImpl; +import com.android.systemui.recents.Recents; +import com.android.systemui.recents.RecentsImplementation; +import com.android.systemui.stackdivider.DividerModule; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.phone.DozeServiceHost; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl; +import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.ShadeControllerImpl; +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.BatteryControllerImpl; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl; +import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.wmshell.WindowManagerShellModule; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; + +/** + * A dagger module for injecting default implementations of components of System UI that may be + * overridden by the System UI implementation. + */ +@Module(includes = { + DividerModule.class, + QSModule.class, + WindowManagerShellModule.class + }, + subcomponents = { + TvSysUIComponent.class + }) +public abstract class TvSystemUIModule { + + @Singleton + @Provides + @Named(LEAK_REPORT_EMAIL_NAME) + @Nullable + static String provideLeakReportEmail() { + return null; + } + + @Binds + abstract EnhancedEstimates bindEnhancedEstimates(EnhancedEstimatesImpl enhancedEstimates); + + @Binds + abstract NotificationLockscreenUserManager bindNotificationLockscreenUserManager( + NotificationLockscreenUserManagerImpl notificationLockscreenUserManager); + + @Provides + @Singleton + static BatteryController provideBatteryController(Context context, + EnhancedEstimates enhancedEstimates, PowerManager powerManager, + BroadcastDispatcher broadcastDispatcher, @Main Handler mainHandler, + @Background Handler bgHandler) { + BatteryController bC = new BatteryControllerImpl(context, enhancedEstimates, powerManager, + broadcastDispatcher, mainHandler, bgHandler); + bC.init(); + return bC; + } + + @Binds + @Singleton + abstract QSFactory bindQSFactory(QSFactoryImpl qsFactoryImpl); + + @Binds + abstract DockManager bindDockManager(DockManagerImpl dockManager); + + @Binds + abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment( + KeyguardEnvironmentImpl keyguardEnvironment); + + @Binds + abstract ShadeController provideShadeController(ShadeControllerImpl shadeController); + + @Singleton + @Provides + @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) + static boolean provideAllowNotificationLongPress() { + return true; + } + + @Singleton + @Provides + static HeadsUpManagerPhone provideHeadsUpManagerPhone( + Context context, + StatusBarStateController statusBarStateController, + KeyguardBypassController bypassController, + NotificationGroupManager groupManager, + ConfigurationController configurationController) { + return new HeadsUpManagerPhone(context, statusBarStateController, bypassController, + groupManager, configurationController); + } + + @Binds + abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone); + + @Provides + @Singleton + static Recents provideRecents(Context context, RecentsImplementation recentsImplementation, + CommandQueue commandQueue) { + return new Recents(context, recentsImplementation, commandQueue); + } + + @Binds + abstract DeviceProvisionedController bindDeviceProvisionedController( + DeviceProvisionedControllerImpl deviceProvisionedController); + + @Binds + abstract KeyguardViewController bindKeyguardViewController( + StatusBarKeyguardViewManager statusBarKeyguardViewManager); + + @Binds + abstract DozeHost provideDozeHost(DozeServiceHost dozeServiceHost); +} diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java index 551b7b41212a..c82b39af4ab3 100644 --- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java @@ -25,13 +25,11 @@ import android.view.View; import com.android.keyguard.KeyguardMessageArea; import com.android.keyguard.KeyguardSliceView; -import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.qs.QSFooterImpl; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QuickQSPanel; import com.android.systemui.qs.QuickStatusBarHeader; import com.android.systemui.qs.customize.QSCustomizer; -import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import java.lang.reflect.InvocationTargetException; @@ -42,8 +40,7 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import dagger.Module; -import dagger.Provides; +import dagger.BindsInstance; import dagger.Subcomponent; /** @@ -54,24 +51,16 @@ import dagger.Subcomponent; public class InjectionInflationController { public static final String VIEW_CONTEXT = "view_context"; - private final ViewCreator mViewCreator; private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>(); private final LayoutInflater.Factory2 mFactory = new InjectionFactory(); + private final ViewInstanceCreator.Factory mViewInstanceCreatorFactory; @Inject - public InjectionInflationController(SystemUIRootComponent rootComponent) { - mViewCreator = rootComponent.createViewCreator(); + public InjectionInflationController(ViewInstanceCreator.Factory viewInstanceCreatorFactory) { + mViewInstanceCreatorFactory = viewInstanceCreatorFactory; initInjectionMap(); } - ArrayMap<String, Method> getInjectionMap() { - return mInjectionMap; - } - - ViewCreator getFragmentCreator() { - return mViewCreator; - } - /** * Wraps a {@link LayoutInflater} to support creating dagger injected views. * See docs/dagger.md for details. @@ -92,25 +81,19 @@ public class InjectionInflationController { } /** - * The subcomponent of dagger that holds all views that need injection. + * Subcomponent that actually creates injected views. */ @Subcomponent - public interface ViewCreator { - /** - * Creates another subcomponent to actually generate the view. - */ - ViewInstanceCreator createInstanceCreator(ViewAttributeProvider attributeProvider); - } - - /** - * Secondary sub-component that actually creates the views. - * - * Having two subcomponents lets us hide the complexity of providing the named context - * and AttributeSet from the SystemUIRootComponent, instead we have one subcomponent that - * creates a new ViewInstanceCreator any time we need to inflate a view. - */ - @Subcomponent(modules = ViewAttributeProvider.class) public interface ViewInstanceCreator { + + /** Factory for creating a ViewInstanceCreator. */ + @Subcomponent.Factory + interface Factory { + ViewInstanceCreator build( + @BindsInstance @Named(VIEW_CONTEXT) Context context, + @BindsInstance AttributeSet attributeSet); + } + /** * Creates the QuickStatusBarHeader. */ @@ -126,11 +109,6 @@ public class InjectionInflationController { NotificationStackScrollLayout createNotificationStackScrollLayout(); /** - * Creates the Shelf. - */ - NotificationShelf creatNotificationShelf(); - - /** * Creates the KeyguardSliceView. */ KeyguardSliceView createKeyguardSliceView(); @@ -156,36 +134,6 @@ public class InjectionInflationController { QSCustomizer createQSCustomizer(); } - /** - * Module for providing view-specific constructor objects. - */ - @Module - public class ViewAttributeProvider { - private final Context mContext; - private final AttributeSet mAttrs; - - private ViewAttributeProvider(Context context, AttributeSet attrs) { - mContext = context; - mAttrs = attrs; - } - - /** - * Provides the view-themed context (as opposed to the global sysui application context). - */ - @Provides - @Named(VIEW_CONTEXT) - public Context provideContext() { - return mContext; - } - - /** - * Provides the AttributeSet for the current view being inflated. - */ - @Provides - public AttributeSet provideAttributeSet() { - return mAttrs; - } - } private class InjectionFactory implements LayoutInflater.Factory2 { @@ -193,10 +141,9 @@ public class InjectionInflationController { public View onCreateView(String name, Context context, AttributeSet attrs) { Method creationMethod = mInjectionMap.get(name); if (creationMethod != null) { - ViewAttributeProvider provider = new ViewAttributeProvider(context, attrs); try { return (View) creationMethod.invoke( - mViewCreator.createInstanceCreator(provider)); + mViewInstanceCreatorFactory.build(context, attrs)); } catch (IllegalAccessException e) { throw new InflateException("Could not inflate " + name, e); } catch (InvocationTargetException e) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 3455ff47de8d..51ad30ebcac6 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -150,6 +150,8 @@ public class VolumeDialogImpl implements VolumeDialog, private boolean mShowing; private boolean mShowA11yStream; + private final boolean mShowLowMediaVolumeIcon; + private int mActiveStream; private int mPrevActiveStream; private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE; @@ -166,7 +168,7 @@ public class VolumeDialogImpl implements VolumeDialog, public VolumeDialogImpl(Context context) { mContext = - new ContextThemeWrapper(context, R.style.qs_theme); + new ContextThemeWrapper(context, R.style.volume_dialog_theme); mController = Dependency.get(VolumeDialogController.class); mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); @@ -175,6 +177,8 @@ public class VolumeDialogImpl implements VolumeDialog, mShowActiveStreamOnly = showActiveStreamOnly(); mHasSeenODICaptionsTooltip = Prefs.getBoolean(context, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false); + mShowLowMediaVolumeIcon = + mContext.getResources().getBoolean(R.bool.config_showLowMediaVolumeIcon); } @Override @@ -421,6 +425,7 @@ public class VolumeDialogImpl implements VolumeDialog, row.dndIcon = row.view.findViewById(R.id.dnd_icon); row.slider = row.view.findViewById(R.id.volume_row_slider); row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row)); + row.number = row.view.findViewById(R.id.volume_number); row.anim = null; @@ -935,6 +940,7 @@ public class VolumeDialogImpl implements VolumeDialog, protected void onStateChangedH(State state) { if (D.BUG) Log.d(TAG, "onStateChangedH() state: " + state.toString()); if (mState != null && state != null + && mState.ringerModeInternal != -1 && mState.ringerModeInternal != state.ringerModeInternal && state.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) { mController.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK)); @@ -1024,19 +1030,28 @@ public class VolumeDialogImpl implements VolumeDialog, final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted; row.icon.setEnabled(iconEnabled); row.icon.setAlpha(iconEnabled ? 1 : 0.5f); - final int iconRes = - isRingVibrate ? R.drawable.ic_volume_ringer_vibrate - : isRingSilent || zenMuted ? row.iconMuteRes - : ss.routedToBluetooth - ? isStreamMuted(ss) ? R.drawable.ic_volume_media_bt_mute - : R.drawable.ic_volume_media_bt - : isStreamMuted(ss) ? row.iconMuteRes : row.iconRes; + final int iconRes; + if (isRingVibrate) { + iconRes = R.drawable.ic_volume_ringer_vibrate; + } else if (isRingSilent || zenMuted) { + iconRes = row.iconMuteRes; + } else if (ss.routedToBluetooth) { + iconRes = isStreamMuted(ss) ? R.drawable.ic_volume_media_bt_mute + : R.drawable.ic_volume_media_bt; + } else if (isStreamMuted(ss)) { + iconRes = row.iconMuteRes; + } else { + iconRes = mShowLowMediaVolumeIcon && ss.level * 2 < (ss.levelMax + ss.levelMin) + ? R.drawable.ic_volume_media_low : row.iconRes; + } + row.icon.setImageResource(iconRes); row.iconState = iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE : (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes) ? Events.ICON_STATE_MUTE - : (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes) + : (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes + || iconRes == R.drawable.ic_volume_media_low) ? Events.ICON_STATE_UNMUTE : Events.ICON_STATE_UNKNOWN; if (iconEnabled) { @@ -1090,6 +1105,7 @@ public class VolumeDialogImpl implements VolumeDialog, final int vlevel = row.ss.muted && (!isRingStream && !zenMuted) ? 0 : row.ss.level; updateVolumeRowSliderH(row, enableSlider, vlevel); + if (row.number != null) row.number.setText(Integer.toString(vlevel)); } private boolean isStreamMuted(final StreamState streamState) { @@ -1115,6 +1131,10 @@ public class VolumeDialogImpl implements VolumeDialog, row.icon.setImageTintList(tint); row.icon.setImageAlpha(alpha); row.cachedTint = tint; + if (row.number != null) { + row.number.setTextColor(tint); + row.number.setAlpha(alpha); + } } private void updateVolumeRowSliderH(VolumeRow row, boolean enable, int vlevel) { @@ -1346,7 +1366,7 @@ public class VolumeDialogImpl implements VolumeDialog, private final class CustomDialog extends Dialog implements DialogInterface { public CustomDialog(Context context) { - super(context, R.style.qs_theme); + super(context, R.style.volume_dialog_theme); } @Override @@ -1458,6 +1478,7 @@ public class VolumeDialogImpl implements VolumeDialog, private TextView header; private ImageButton icon; private SeekBar slider; + private TextView number; private int stream; private StreamState ss; private long userAttempt; // last user-driven slider change diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index 4c0762e4ea32..0d52e4fefd3e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -79,7 +79,9 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { .thenReturn(mMockKeyguardSliceView); InjectionInflationController inflationController = new InjectionInflationController( - SystemUIFactory.getInstance().getRootComponent()); + SystemUIFactory.getInstance() + .getRootComponent() + .createViewInstanceCreatorFactory()); LayoutInflater layoutInflater = inflationController .injectable(LayoutInflater.from(getContext())); layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java index e6c2ddcf7e65..aa4db3205d82 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java @@ -65,7 +65,9 @@ public class KeyguardPresentationTest extends SysuiTestCase { allowTestableLooperAsMainThread(); InjectionInflationController inflationController = new InjectionInflationController( - SystemUIFactory.getInstance().getRootComponent()); + SystemUIFactory.getInstance() + .getRootComponent() + .createViewInstanceCreatorFactory()); mLayoutInflater = inflationController.injectable(LayoutInflater.from(mContext)); mLayoutInflater.setPrivateFactory(new LayoutInflater.Factory2() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java index bc3c3d995ce6..560d581c20e7 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java @@ -51,7 +51,9 @@ public class KeyguardStatusViewTest extends SysuiTestCase { allowTestableLooperAsMainThread(); mDependency.injectMockDependency(KeyguardUpdateMonitor.class); InjectionInflationController inflationController = new InjectionInflationController( - SystemUIFactory.getInstance().getRootComponent()); + SystemUIFactory.getInstance() + .getRootComponent() + .createViewInstanceCreatorFactory()); LayoutInflater layoutInflater = inflationController .injectable(LayoutInflater.from(getContext())); mKeyguardStatusView = diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java index fbc8e9d8de79..ac567e0ae67d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java @@ -25,6 +25,7 @@ import android.content.Context; import android.os.RemoteException; import android.provider.Settings; import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import android.view.Display; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IWindowMagnificationConnection; @@ -47,6 +48,7 @@ import org.mockito.MockitoAnnotations; */ @SmallTest @RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper public class IWindowMagnificationConnectionTest extends SysuiTestCase { private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY; @@ -57,7 +59,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { @Mock private IWindowMagnificationConnectionCallback mConnectionCallback; @Mock - private WindowMagnificationController mWindowMagnificationController; + private WindowMagnificationAnimationController mWindowMagnificationAnimationController; @Mock private ModeSwitchesController mModeSwitchesController; private IWindowMagnificationConnection mIWindowMagnificationConnection; @@ -74,7 +76,8 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { any(IWindowMagnificationConnection.class)); mWindowMagnification = new WindowMagnification(getContext(), getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController); - mWindowMagnification.mWindowMagnificationController = mWindowMagnificationController; + mWindowMagnification.mWindowMagnificationAnimationController = + mWindowMagnificationAnimationController; mWindowMagnification.requestWindowMagnificationConnection(true); assertNotNull(mIWindowMagnificationConnection); mIWindowMagnificationConnection.setConnectionCallback(mConnectionCallback); @@ -86,7 +89,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { Float.NaN); waitForIdleSync(); - verify(mWindowMagnificationController).enableWindowMagnification(3.0f, Float.NaN, + verify(mWindowMagnificationAnimationController).enableWindowMagnification(3.0f, Float.NaN, Float.NaN); } @@ -99,7 +102,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY); waitForIdleSync(); - verify(mWindowMagnificationController).deleteWindowMagnification(); + verify(mWindowMagnificationAnimationController).deleteWindowMagnification(); } @Test @@ -107,7 +110,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { mIWindowMagnificationConnection.setScale(TEST_DISPLAY, 3.0f); waitForIdleSync(); - verify(mWindowMagnificationController).setScale(3.0f); + verify(mWindowMagnificationAnimationController).setScale(3.0f); } @Test @@ -115,7 +118,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { mIWindowMagnificationConnection.moveWindowMagnifier(TEST_DISPLAY, 100f, 200f); waitForIdleSync(); - verify(mWindowMagnificationController).moveWindowMagnifier(100f, 200f); + verify(mWindowMagnificationAnimationController).moveWindowMagnifier(100f, 200f); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java new file mode 100644 index 000000000000..b7c198e53cfa --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.animation.ValueAnimator; +import android.app.Instrumentation; +import android.content.Context; +import android.os.Handler; +import android.os.SystemClock; +import android.testing.AndroidTestingRunner; +import android.view.SurfaceControl; +import android.view.animation.AccelerateInterpolator; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.MediumTest; + +import com.android.internal.graphics.SfVsyncFrameCallbackProvider; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.concurrent.atomic.AtomicReference; + + +@MediumTest +@RunWith(AndroidTestingRunner.class) +public class WindowMagnificationAnimationControllerTest extends SysuiTestCase { + + private static final float DEFAULT_SCALE = 3.0f; + private static final float DEFAULT_CENTER_X = 400.0f; + private static final float DEFAULT_CENTER_Y = 500.0f; + // The duration couldn't too short, otherwise the ValueAnimator won't work in expectation. + private static final long ANIMATION_DURATION_MS = 200; + + private AtomicReference<Float> mCurrentScale = new AtomicReference<>((float) 0); + private AtomicReference<Float> mCurrentCenterX = new AtomicReference<>((float) 0); + private AtomicReference<Float> mCurrentCenterY = new AtomicReference<>((float) 0); + private ArgumentCaptor<Float> mScaleCaptor = ArgumentCaptor.forClass(Float.class); + private ArgumentCaptor<Float> mCenterXCaptor = ArgumentCaptor.forClass(Float.class); + private ArgumentCaptor<Float> mCenterYCaptor = ArgumentCaptor.forClass(Float.class); + + @Mock + Handler mHandler; + @Mock + SfVsyncFrameCallbackProvider mSfVsyncFrameProvider; + @Mock + WindowMagnifierCallback mWindowMagnifierCallback; + + private SpyWindowMagnificationController mController; + private WindowMagnificationController mSpyController; + private WindowMagnificationAnimationController mWindowMagnificationAnimationController; + private Instrumentation mInstrumentation; + private long mWaitingAnimationPeriod; + private long mWaitIntermediateAnimationPeriod; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mWaitingAnimationPeriod = ANIMATION_DURATION_MS + 50; + mWaitIntermediateAnimationPeriod = ANIMATION_DURATION_MS / 2; + mController = new SpyWindowMagnificationController(mContext, mHandler, + mSfVsyncFrameProvider, null, new SurfaceControl.Transaction(), + mWindowMagnifierCallback); + mSpyController = mController.getSpyController(); + mWindowMagnificationAnimationController = new WindowMagnificationAnimationController( + mContext, mController, newValueAnimator()); + } + + @Test + public void enableWindowMagnification_disabled_expectedStartAndEndValues() { + enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); + + verify(mSpyController, atLeast(2)).enableWindowMagnification( + mScaleCaptor.capture(), + mCenterXCaptor.capture(), mCenterYCaptor.capture()); + verifyStartValue(mScaleCaptor, 1.0f); + verifyStartValue(mCenterXCaptor, DEFAULT_CENTER_X); + verifyStartValue(mCenterYCaptor, DEFAULT_CENTER_Y); + verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y); + } + + @Test + public void enableWindowMagnification_enabling_expectedStartAndEndValues() { + enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod); + final float targetScale = DEFAULT_SCALE + 1.0f; + final float targetCenterX = DEFAULT_CENTER_X + 100; + final float targetCenterY = DEFAULT_CENTER_Y + 100; + + mInstrumentation.runOnMainSync(() -> { + Mockito.reset(mSpyController); + mWindowMagnificationAnimationController.enableWindowMagnification(targetScale, + targetCenterX, targetCenterY); + mCurrentScale.set(mController.getScale()); + mCurrentCenterX.set(mController.getCenterX()); + mCurrentCenterY.set(mController.getCenterY()); + }); + + SystemClock.sleep(mWaitingAnimationPeriod); + + verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(), + mCenterXCaptor.capture(), mCenterYCaptor.capture()); + verifyStartValue(mScaleCaptor, mCurrentScale.get()); + verifyStartValue(mCenterXCaptor, mCurrentCenterX.get()); + verifyStartValue(mCenterYCaptor, mCurrentCenterY.get()); + verifyFinalSpec(targetScale, targetCenterX, targetCenterY); + } + + @Test + public void enableWindowMagnification_disabling_expectedStartAndEndValues() { + enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); + deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod); + final float targetScale = DEFAULT_SCALE + 1.0f; + final float targetCenterX = DEFAULT_CENTER_X + 100; + final float targetCenterY = DEFAULT_CENTER_Y + 100; + + mInstrumentation.runOnMainSync( + () -> { + Mockito.reset(mSpyController); + mWindowMagnificationAnimationController.enableWindowMagnification(targetScale, + targetCenterX, targetCenterY); + mCurrentScale.set(mController.getScale()); + mCurrentCenterX.set(mController.getCenterX()); + mCurrentCenterY.set(mController.getCenterY()); + }); + SystemClock.sleep(mWaitingAnimationPeriod); + + verify(mSpyController, atLeast(2)).enableWindowMagnification( + mScaleCaptor.capture(), + mCenterXCaptor.capture(), mCenterYCaptor.capture()); + //Animating in reverse, so we only check if the start values are greater than current. + assertTrue(mScaleCaptor.getAllValues().get(0) > mCurrentScale.get()); + assertEquals(targetScale, mScaleCaptor.getValue(), 0f); + assertTrue(mCenterXCaptor.getAllValues().get(0) > mCurrentCenterX.get()); + assertEquals(targetCenterX, mCenterXCaptor.getValue(), 0f); + assertTrue(mCenterYCaptor.getAllValues().get(0) > mCurrentCenterY.get()); + assertEquals(targetCenterY, mCenterYCaptor.getValue(), 0f); + verifyFinalSpec(targetScale, targetCenterX, targetCenterY); + } + + @Test + public void enableWindowMagnificationWithSameScale_doNothing() { + enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); + + enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); + + verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(), + anyFloat()); + } + + @Test + public void setScale_enabled_expectedScale() { + enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); + + mInstrumentation.runOnMainSync( + () -> mWindowMagnificationAnimationController.setScale(DEFAULT_SCALE + 1)); + + verify(mSpyController).setScale(DEFAULT_SCALE + 1); + verifyFinalSpec(DEFAULT_SCALE + 1, DEFAULT_CENTER_X, DEFAULT_CENTER_Y); + } + + @Test + public void deleteWindowMagnification_enabled_expectedStartAndEndValues() { + enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); + + deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); + + verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(), + mCenterXCaptor.capture(), mCenterYCaptor.capture()); + verify(mSpyController).deleteWindowMagnification(); + verifyStartValue(mScaleCaptor, DEFAULT_SCALE); + verifyStartValue(mCenterXCaptor, Float.NaN); + verifyStartValue(mCenterYCaptor, Float.NaN); + verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); + } + + @Test + public void deleteWindowMagnification_disabled_doNothing() { + deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); + + Mockito.verifyNoMoreInteractions(mSpyController); + } + + @Test + public void deleteWindowMagnification_enabling_checkStartAndEndValues() { + enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod); + + //It just reverse the animation, so we don't need to wait the whole duration. + mInstrumentation.runOnMainSync( + () -> { + Mockito.reset(mSpyController); + mWindowMagnificationAnimationController.deleteWindowMagnification(); + mCurrentScale.set(mController.getScale()); + mCurrentCenterX.set(mController.getCenterX()); + mCurrentCenterY.set(mController.getCenterY()); + }); + SystemClock.sleep(mWaitingAnimationPeriod); + + verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(), + mCenterXCaptor.capture(), mCenterYCaptor.capture()); + verify(mSpyController).deleteWindowMagnification(); + + //The animation is in verse, so we only check the start values should no be greater than + // the current one. + assertTrue(mScaleCaptor.getAllValues().get(0) <= mCurrentScale.get()); + assertEquals(1.0f, mScaleCaptor.getValue(), 0f); + verifyStartValue(mCenterXCaptor, Float.NaN); + verifyStartValue(mCenterYCaptor, Float.NaN); + verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); + } + + @Test + public void deleteWindowMagnification_disabling_checkStartAndValues() { + enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); + deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod); + + deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); + + verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(), + mCenterXCaptor.capture(), mCenterYCaptor.capture()); + verify(mSpyController).deleteWindowMagnification(); + assertEquals(1.0f, mScaleCaptor.getValue(), 0f); + verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); + } + + @Test + public void moveWindowMagnifier_enabled() { + enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); + + mInstrumentation.runOnMainSync( + () -> mWindowMagnificationAnimationController.moveWindowMagnifier(100f, 200f)); + + verify(mSpyController).moveWindowMagnifier(100f, 200f); + verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + 100f, DEFAULT_CENTER_Y + 100f); + } + + @Test + public void onConfigurationChanged_passThrough() { + mWindowMagnificationAnimationController.onConfigurationChanged(100); + + verify(mSpyController).onConfigurationChanged(100); + } + private void verifyFinalSpec(float expectedScale, float expectedCenterX, + float expectedCenterY) { + assertEquals(expectedScale, mController.getScale(), 0f); + assertEquals(expectedCenterX, mController.getCenterX(), 0f); + assertEquals(expectedCenterY, mController.getCenterY(), 0f); + } + + private void enableWindowMagnificationAndWaitAnimating(long duration) { + mInstrumentation.runOnMainSync( + () -> { + Mockito.reset(mSpyController); + mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE, + DEFAULT_CENTER_X, DEFAULT_CENTER_Y); + }); + SystemClock.sleep(duration); + } + + private void deleteWindowMagnificationAndWaitAnimating(long duration) { + mInstrumentation.runOnMainSync( + () -> { + resetMockObjects(); + mWindowMagnificationAnimationController.deleteWindowMagnification(); + }); + SystemClock.sleep(duration); + } + + private void verifyStartValue(ArgumentCaptor<Float> captor, float startValue) { + assertEquals(startValue, captor.getAllValues().get(0), 0f); + } + + private void resetMockObjects() { + Mockito.reset(mSpyController); + } + + /** + * It observes the methods in {@link WindowMagnificationController} since we couldn't spy it + * directly. + */ + private static class SpyWindowMagnificationController extends WindowMagnificationController { + private WindowMagnificationController mSpyController; + + SpyWindowMagnificationController(Context context, Handler handler, + SfVsyncFrameCallbackProvider sfVsyncFrameProvider, + MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction, + WindowMagnifierCallback callback) { + super(context, handler, sfVsyncFrameProvider, mirrorWindowControl, transaction, + callback); + mSpyController = Mockito.mock(WindowMagnificationController.class); + } + + WindowMagnificationController getSpyController() { + return mSpyController; + } + + @Override + void enableWindowMagnification(float scale, float centerX, float centerY) { + super.enableWindowMagnification(scale, centerX, centerY); + mSpyController.enableWindowMagnification(scale, centerX, centerY); + } + + @Override + void deleteWindowMagnification() { + super.deleteWindowMagnification(); + mSpyController.deleteWindowMagnification(); + } + + @Override + void moveWindowMagnifier(float offsetX, float offsetY) { + super.moveWindowMagnifier(offsetX, offsetX); + mSpyController.moveWindowMagnifier(offsetX, offsetY); + } + + @Override + void setScale(float scale) { + super.setScale(scale); + mSpyController.setScale(scale); + } + + @Override + void onConfigurationChanged(int configDiff) { + super.onConfigurationChanged(configDiff); + mSpyController.onConfigurationChanged(configDiff); + } + + } + + private static ValueAnimator newValueAnimator() { + final ValueAnimator valueAnimator = new ValueAnimator(); + valueAnimator.setDuration(ANIMATION_DURATION_MS); + valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f)); + valueAnimator.setFloatValues(0.0f, 1.0f); + return valueAnimator; + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java index 2007fbb8fc6c..f1f394e70689 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -18,6 +18,7 @@ package com.android.systemui.accessibility; import static android.view.Choreographer.FrameCallback; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.atLeastOnce; @@ -26,8 +27,12 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Instrumentation; +import android.content.Context; +import android.content.pm.ActivityInfo; import android.os.Handler; import android.testing.AndroidTestingRunner; +import android.view.Display; +import android.view.Surface; import android.view.SurfaceControl; import androidx.test.InstrumentationRegistry; @@ -41,6 +46,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @SmallTest @@ -57,12 +63,14 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { WindowMagnifierCallback mWindowMagnifierCallback; @Mock SurfaceControl.Transaction mTransaction; + private Context mContext; private WindowMagnificationController mWindowMagnificationController; private Instrumentation mInstrumentation; @Before public void setUp() { MockitoAnnotations.initMocks(this); + mContext = Mockito.spy(getContext()); mInstrumentation = InstrumentationRegistry.getInstrumentation(); doAnswer(invocation -> { FrameCallback callback = invocation.getArgument(0); @@ -73,8 +81,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { when(mTransaction.remove(any())).thenReturn(mTransaction); when(mTransaction.setGeometry(any(), any(), any(), anyInt())).thenReturn(mTransaction); - - mWindowMagnificationController = new WindowMagnificationController(getContext(), + mWindowMagnificationController = new WindowMagnificationController(mContext, mHandler, mSfVsyncFrameProvider, mMirrorWindowControl, mTransaction, mWindowMagnifierCallback); verify(mMirrorWindowControl).setWindowDelegate( @@ -83,9 +90,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { @After public void tearDown() { - mInstrumentation.runOnMainSync(() -> { - mWindowMagnificationController.deleteWindowMagnification(); - }); + mInstrumentation.runOnMainSync( + () -> mWindowMagnificationController.deleteWindowMagnification()); } @Test @@ -121,4 +127,27 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { verify(mSfVsyncFrameProvider, atLeastOnce()).postFrameCallback(any()); } + + @Test + public void setScale_enabled_expectedValue() { + mInstrumentation.runOnMainSync( + () -> mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN, + Float.NaN)); + + mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.setScale(3.0f)); + + assertEquals(3.0f, mWindowMagnificationController.getScale(), 0); + } + + @Test + public void onConfigurationChanged_disabled_withoutException() { + Display display = Mockito.spy(mContext.getDisplay()); + when(display.getRotation()).thenReturn(Surface.ROTATION_90); + when(mContext.getDisplay()).thenReturn(display); + + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY); + mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION); + }); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java index 41360130ac65..936558bca2d2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java @@ -26,6 +26,7 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.RemoteException; import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import android.view.Display; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IWindowMagnificationConnection; @@ -45,6 +46,7 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper public class WindowMagnificationTest extends SysuiTestCase { @Mock diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java index 4fdc06e64e2c..8f082c15df36 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java @@ -27,6 +27,9 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -34,6 +37,8 @@ import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.content.pm.PackageManager; +import android.media.AudioManager; +import android.media.AudioRecordingConfiguration; import android.os.Looper; import android.os.UserHandle; import android.testing.AndroidTestingRunner; @@ -47,9 +52,11 @@ import com.android.systemui.dump.DumpManager; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Collections; import java.util.List; @SmallTest @@ -73,6 +80,12 @@ public class AppOpsControllerTest extends SysuiTestCase { private PermissionFlagsCache mFlagsCache; @Mock private PackageManager mPackageManager; + @Mock(stubOnly = true) + private AudioManager mAudioManager; + @Mock(stubOnly = true) + private AudioManager.AudioRecordingCallback mRecordingCallback; + @Mock(stubOnly = true) + private AudioRecordingConfiguration mPausedMockRecording; private AppOpsControllerImpl mController; private TestableLooper mTestableLooper; @@ -94,11 +107,20 @@ public class AppOpsControllerTest extends SysuiTestCase { when(mFlagsCache.getPermissionFlags(anyString(), anyString(), eq(TEST_UID_NON_USER_SENSITIVE))).thenReturn(0); + doAnswer((invocation) -> mRecordingCallback = invocation.getArgument(0)) + .when(mAudioManager).registerAudioRecordingCallback(any(), any()); + when(mPausedMockRecording.getClientUid()).thenReturn(TEST_UID); + when(mPausedMockRecording.isClientSilenced()).thenReturn(true); + + when(mAudioManager.getActiveRecordingConfigurations()) + .thenReturn(List.of(mPausedMockRecording)); + mController = new AppOpsControllerImpl( mContext, mTestableLooper.getLooper(), mDumpManager, - mFlagsCache + mFlagsCache, + mAudioManager ); } @@ -363,6 +385,89 @@ public class AppOpsControllerTest extends SysuiTestCase { AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); } + @Test + public void testPausedRecordingIsRetrievedOnCreation() { + mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); + mTestableLooper.processAllMessages(); + + mController.onOpActiveChanged( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + + verify(mCallback, never()) + .onActiveStateChanged(anyInt(), anyInt(), anyString(), anyBoolean()); + } + + @Test + public void testPausedRecordingFilteredOut() { + mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); + mTestableLooper.processAllMessages(); + + mController.onOpActiveChanged( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + + assertTrue(mController.getActiveAppOps().isEmpty()); + } + + @Test + public void testOnlyRecordAudioPaused() { + mController.addCallback(new int[]{ + AppOpsManager.OP_RECORD_AUDIO, + AppOpsManager.OP_CAMERA + }, mCallback); + mTestableLooper.processAllMessages(); + + mController.onOpActiveChanged( + AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + + verify(mCallback).onActiveStateChanged( + AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true); + List<AppOpItem> list = mController.getActiveAppOps(); + + assertEquals(1, list.size()); + assertEquals(AppOpsManager.OP_CAMERA, list.get(0).getCode()); + } + + @Test + public void testUnpausedRecordingSentActive() { + mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); + mTestableLooper.processAllMessages(); + mController.onOpActiveChanged( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); + + mTestableLooper.processAllMessages(); + mRecordingCallback.onRecordingConfigChanged(Collections.emptyList()); + + mTestableLooper.processAllMessages(); + + verify(mCallback).onActiveStateChanged( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); + } + + @Test + public void testAudioPausedSentInactive() { + mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); + mTestableLooper.processAllMessages(); + mController.onOpActiveChanged( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + + AudioRecordingConfiguration mockARC = mock(AudioRecordingConfiguration.class); + when(mockARC.getClientUid()).thenReturn(TEST_UID_OTHER); + when(mockARC.isClientSilenced()).thenReturn(true); + + mRecordingCallback.onRecordingConfigChanged(List.of(mockARC)); + mTestableLooper.processAllMessages(); + + InOrder inOrder = inOrder(mCallback); + inOrder.verify(mCallback).onActiveStateChanged( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); + inOrder.verify(mCallback).onActiveStateChanged( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, false); + } + private class TestHandler extends AppOpsControllerImpl.H { TestHandler(Looper looper) { mController.super(looper); diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index b7589534a770..5c86fcb6b008 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -60,6 +60,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.statusbar.IStatusBarService; +import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dump.DumpManager; @@ -70,7 +71,9 @@ import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationRemoveInterceptor; +import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.RankingBuilder; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -79,8 +82,10 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; +import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.LockscreenLockIconController; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; @@ -90,6 +95,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.FloatingContentCoordinator; +import com.android.systemui.util.InjectionInflationController; import com.google.common.collect.ImmutableList; @@ -174,6 +180,8 @@ public class BubbleControllerTest extends SysuiTestCase { @Mock private ShadeController mShadeController; @Mock + private NotificationShelfComponent mNotificationShelfComponent; + @Mock private NotifPipeline mNotifPipeline; @Mock private FeatureFlags mFeatureFlagsOldPipeline; @@ -185,11 +193,14 @@ public class BubbleControllerTest extends SysuiTestCase { private IStatusBarService mStatusBarService; @Mock private LauncherApps mLauncherApps; + @Mock private LockscreenLockIconController mLockIconController; private BubbleData mBubbleData; private TestableLooper mTestableLooper; + private SuperStatusBarViewFactory mSuperStatusBarViewFactory; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -199,6 +210,24 @@ public class BubbleControllerTest extends SysuiTestCase { mContext.addMockSystemService(FaceManager.class, mFaceManager); when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); + mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext, + new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent() + .createViewInstanceCreatorFactory()), + new NotificationShelfComponent.Builder() { + @Override + public NotificationShelfComponent.Builder notificationShelf( + NotificationShelf view) { + return this; + } + + @Override + public NotificationShelfComponent build() { + return mNotificationShelfComponent; + } + }, + mLockIconController); + + // Bubbles get added to status bar window view mNotificationShadeWindowController = new NotificationShadeWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, mConfigurationController, mKeyguardViewMediator, mKeyguardBypassController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java index 43bf19111049..196aa65bd28f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -58,6 +58,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.statusbar.IStatusBarService; +import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dump.DumpManager; @@ -66,7 +67,9 @@ import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.RankingBuilder; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; @@ -75,7 +78,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; -import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; +import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.LockscreenLockIconController; @@ -88,6 +91,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.FloatingContentCoordinator; +import com.android.systemui.util.InjectionInflationController; import org.junit.Before; import org.junit.Ignore; @@ -168,7 +172,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { @Mock private ShadeController mShadeController; @Mock - private NotificationRowComponent mNotificationRowComponent; + private NotificationShelfComponent mNotificationShelfComponent; @Mock private NotifPipeline mNotifPipeline; @Mock @@ -185,6 +189,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { private BubbleData mBubbleData; private TestableLooper mTestableLooper; + private SuperStatusBarViewFactory mSuperStatusBarViewFactory; @Before public void setUp() throws Exception { @@ -195,6 +200,23 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { mContext.addMockSystemService(FaceManager.class, mFaceManager); when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); + mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext, + new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent() + .createViewInstanceCreatorFactory()), + new NotificationShelfComponent.Builder() { + @Override + public NotificationShelfComponent.Builder notificationShelf( + NotificationShelf view) { + return this; + } + + @Override + public NotificationShelfComponent build() { + return mNotificationShelfComponent; + } + }, + mLockIconController); + // Bubbles get added to status bar window view mNotificationShadeWindowController = new NotificationShadeWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index f70fb4f55a8d..d1f505baa9e3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -254,16 +254,12 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { int mCleanDateFormatInvokations; private int mCounter; - Uri getUri() { - return mSliceUri; - } + TestableKeyguardSliceProvider() { + super(); - @Override - protected void inject() { mAlarmManager = KeyguardSliceProviderTest.this.mAlarmManager; mContentResolver = KeyguardSliceProviderTest.this.mContentResolver; mZenModeController = KeyguardSliceProviderTest.this.mZenModeController; - mMediaWakeLock = KeyguardSliceProviderTest.this.mMediaWakeLock; mDozeParameters = KeyguardSliceProviderTest.this.mDozeParameters; mNextAlarmController = KeyguardSliceProviderTest.this.mNextAlarmController; mStatusBarStateController = KeyguardSliceProviderTest.this.mStatusBarStateController; @@ -272,6 +268,17 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { } @Override + public boolean onCreateSliceProvider() { + boolean result = super.onCreateSliceProvider(); + mMediaWakeLock = KeyguardSliceProviderTest.this.mMediaWakeLock; + return result; + } + + Uri getUri() { + return mSliceUri; + } + + @Override protected boolean isDndOn() { return mIsZenMode; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 90e9ef4e9c56..98a6ced91af6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -46,6 +46,7 @@ import com.android.systemui.statusbar.phone.NavigationModeController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; +import com.android.systemui.util.InjectionInflationController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -71,6 +72,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock PowerManager mPowerManager; private @Mock TrustManager mTrustManager; private @Mock NavigationModeController mNavigationModeController; + private @Mock InjectionInflationController mInjectionInflationController; private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); @@ -88,7 +90,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher, () -> mStatusBarKeyguardViewManager, mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor, - mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController); + mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController, + mInjectionInflationController); mViewMediator.start(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java index 492b33e3c4a6..2e794a40d238 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java @@ -83,8 +83,8 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { mManager.addListener(mListener); mMediaData = new MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, - new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, true, null, false, - KEY, false); + new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, true, null, true, + false, KEY, false); mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt index 3789e6ef1f65..a4ebe1ff2a4e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -13,6 +13,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dump.DumpManager +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.SbnBuilder import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.eq @@ -58,6 +59,7 @@ class MediaDataManagerTest : SysuiTestCase() { @Mock lateinit var mediaTimeoutListener: MediaTimeoutListener @Mock lateinit var mediaResumeListener: MediaResumeListener @Mock lateinit var pendingIntent: PendingIntent + @Mock lateinit var activityStarter: ActivityStarter @JvmField @Rule val mockito = MockitoJUnit.rule() lateinit var mediaDataManager: MediaDataManager lateinit var mediaNotification: StatusBarNotification @@ -68,8 +70,8 @@ class MediaDataManagerTest : SysuiTestCase() { backgroundExecutor = FakeExecutor(FakeSystemClock()) mediaDataManager = MediaDataManager(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory, broadcastDispatcher, dumpManager, - mediaTimeoutListener, mediaResumeListener, useMediaResumption = true, - useQsMediaPlayer = true) + mediaTimeoutListener, mediaResumeListener, activityStarter, + useMediaResumption = true, useQsMediaPlayer = true) session = MediaSession(context, "MediaDataManagerTestSession") mediaNotification = SbnBuilder().run { setPkg(PACKAGE_NAME) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt new file mode 100644 index 000000000000..118cffc2d5b8 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.media + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.mock +import org.mockito.Mockito.`when` as whenever + +@SmallTest +@RunWith(AndroidTestingRunner::class) +public class MediaPlayerDataTest : SysuiTestCase() { + + companion object { + val LOCAL = true + val RESUMPTION = true + } + + @Before + fun setup() { + MediaPlayerData.clear() + } + + @Test + fun addPlayingThenRemote() { + val playerIsPlaying = mock(MediaControlPanel::class.java) + whenever(playerIsPlaying.isPlaying).thenReturn(true) + val dataIsPlaying = createMediaData(LOCAL, !RESUMPTION) + + val playerIsRemote = mock(MediaControlPanel::class.java) + whenever(playerIsRemote.isPlaying).thenReturn(false) + val dataIsRemote = createMediaData(!LOCAL, !RESUMPTION) + + MediaPlayerData.addMediaPlayer("1", dataIsPlaying, playerIsPlaying) + MediaPlayerData.addMediaPlayer("2", dataIsRemote, playerIsRemote) + + val players = MediaPlayerData.players() + assertThat(players).hasSize(2) + assertThat(players).containsExactly(playerIsPlaying, playerIsRemote).inOrder() + } + + @Test + fun switchPlayersPlaying() { + val playerIsPlaying1 = mock(MediaControlPanel::class.java) + whenever(playerIsPlaying1.isPlaying).thenReturn(true) + val dataIsPlaying1 = createMediaData(LOCAL, !RESUMPTION) + + val playerIsPlaying2 = mock(MediaControlPanel::class.java) + whenever(playerIsPlaying2.isPlaying).thenReturn(false) + val dataIsPlaying2 = createMediaData(LOCAL, !RESUMPTION) + + MediaPlayerData.addMediaPlayer("1", dataIsPlaying1, playerIsPlaying1) + MediaPlayerData.addMediaPlayer("2", dataIsPlaying2, playerIsPlaying2) + + whenever(playerIsPlaying1.isPlaying).thenReturn(false) + whenever(playerIsPlaying2.isPlaying).thenReturn(true) + + MediaPlayerData.addMediaPlayer("1", dataIsPlaying1, playerIsPlaying1) + MediaPlayerData.addMediaPlayer("2", dataIsPlaying2, playerIsPlaying2) + + val players = MediaPlayerData.players() + assertThat(players).hasSize(2) + assertThat(players).containsExactly(playerIsPlaying2, playerIsPlaying1).inOrder() + } + + @Test + fun fullOrderTest() { + val playerIsPlaying = mock(MediaControlPanel::class.java) + whenever(playerIsPlaying.isPlaying).thenReturn(true) + val dataIsPlaying = createMediaData(LOCAL, !RESUMPTION) + + val playerIsPlayingAndRemote = mock(MediaControlPanel::class.java) + whenever(playerIsPlayingAndRemote.isPlaying).thenReturn(true) + val dataIsPlayingAndRemote = createMediaData(!LOCAL, !RESUMPTION) + + val playerIsStoppedAndLocal = mock(MediaControlPanel::class.java) + whenever(playerIsStoppedAndLocal.isPlaying).thenReturn(false) + val dataIsStoppedAndLocal = createMediaData(LOCAL, !RESUMPTION) + + val playerIsStoppedAndRemote = mock(MediaControlPanel::class.java) + whenever(playerIsStoppedAndLocal.isPlaying).thenReturn(false) + val dataIsStoppedAndRemote = createMediaData(!LOCAL, !RESUMPTION) + + val playerCanResume = mock(MediaControlPanel::class.java) + whenever(playerCanResume.isPlaying).thenReturn(false) + val dataCanResume = createMediaData(LOCAL, RESUMPTION) + + MediaPlayerData.addMediaPlayer("3", dataIsStoppedAndLocal, playerIsStoppedAndLocal) + MediaPlayerData.addMediaPlayer("5", dataIsStoppedAndRemote, playerIsStoppedAndRemote) + MediaPlayerData.addMediaPlayer("4", dataCanResume, playerCanResume) + MediaPlayerData.addMediaPlayer("1", dataIsPlaying, playerIsPlaying) + MediaPlayerData.addMediaPlayer("2", dataIsPlayingAndRemote, playerIsPlayingAndRemote) + + val players = MediaPlayerData.players() + assertThat(players).hasSize(5) + assertThat(players).containsExactly(playerIsPlaying, playerIsPlayingAndRemote, + playerIsStoppedAndLocal, playerCanResume, playerIsStoppedAndRemote).inOrder() + } + + private fun createMediaData(isLocalSession: Boolean, resumption: Boolean) = + MediaData(0, false, 0, null, null, null, null, null, emptyList(), emptyList<Int>(), "", + null, null, null, true, null, isLocalSession, resumption, null, false) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index d338cbf51fb5..9922d3620a57 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -150,7 +150,10 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { return new QSFragment( new RemoteInputQuickSettingsDisabler(context, mock(ConfigurationController.class), commandQueue), - new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()), + new InjectionInflationController( + SystemUIFactory.getInstance() + .getRootComponent() + .createViewInstanceCreatorFactory()), mock(QSTileHost.class), mock(StatusBarStateController.class), commandQueue, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index bdb7166f5db1..c8e1a74d969f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -78,7 +78,7 @@ import javax.inject.Provider; @RunWith(AndroidTestingRunner.class) @SmallTest -@RunWithLooper +@RunWithLooper(setAsMainLooper = true) public class QSTileHostTest extends SysuiTestCase { private static String MOCK_STATE_STRING = "MockState"; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt index c2579dd46e78..3aa40dec1fad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt @@ -53,7 +53,7 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidTestingRunner::class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper(setAsMainLooper = true) class CustomTileTest : SysuiTestCase() { companion object { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt index f70106a64968..2006a75c0e16 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt @@ -38,7 +38,7 @@ import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) -@RunWithLooper +@RunWithLooper(setAsMainLooper = true) @SmallTest class BatterySaverTileTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java index 8ece62281f77..5d14898cdd2c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java @@ -58,7 +58,7 @@ import java.util.List; @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class CastTileTest extends SysuiTestCase { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 14994d55852f..54ccc4d8320d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -79,7 +79,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -117,7 +117,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private VisualStabilityManager mVisualStabilityManager; @Mock private NotificationPresenter mPresenter; @Mock private NotificationActivityStarter mNotificationActivityStarter; - @Mock private NotificationStackScrollLayout mStackScroller; + @Mock private NotificationListContainer mNotificationListContainer; @Mock private NotificationInfo.CheckSaveListener mCheckSaveListener; @Mock private OnSettingsClickListener mOnSettingsClickListener; @Mock private DeviceProvisionedController mDeviceProvisionedController; @@ -156,7 +156,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mChannelEditorDialogController, mContextTracker, mProvider, mAssistantFeedbackController, mBubbleController, new UiEventLoggerFake()); - mGutsManager.setUpWithPresenter(mPresenter, mStackScroller, + mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer, mCheckSaveListener, mOnSettingsClickListener); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index ddac2ecbd6eb..fec467706b7b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -64,6 +64,7 @@ import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -197,7 +198,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mEntryManager.setUpWithPresenter(mock(NotificationPresenter.class)); when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false); + NotificationShelfController notificationShelfController = + mock(NotificationShelfController.class); NotificationShelf notificationShelf = mock(NotificationShelf.class); + when(notificationShelfController.getView()).thenReturn(notificationShelf); when(mNotificationSectionsManager.createSectionsForBuckets()).thenReturn( new NotificationSection[]{ mNotificationSection @@ -208,7 +212,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { // holds a copy of the CUT's instances of these KeyguardBypassController, so they still // refer to the CUT's member variables, not the spy's member variables. mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null, - true /* allowLongPress */, mNotificationRoundnessManager, + mNotificationRoundnessManager, mock(DynamicPrivacyController.class), mock(SysuiStatusBarStateController.class), mHeadsUpManager, @@ -230,7 +234,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture()); mUserChangedListener = userChangedCaptor.getValue(); mStackScroller = spy(mStackScrollerInternal); - mStackScroller.setShelf(notificationShelf); + mStackScroller.setShelfController(notificationShelfController); mStackScroller.setStatusBar(mBar); mStackScroller.setScrimController(mock(ScrimController.class)); mStackScroller.setGroupManager(mGroupManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java index e546dff8abf6..8dea84c4d0b6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java @@ -38,7 +38,7 @@ import com.android.systemui.statusbar.HeadsUpStatusBarView; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Assert; @@ -51,8 +51,8 @@ import org.junit.runner.RunWith; @RunWithLooper public class HeadsUpAppearanceControllerTest extends SysuiTestCase { - private final NotificationStackScrollLayout mStackScroller = - mock(NotificationStackScrollLayout.class); + private final NotificationStackScrollLayoutController mStackScrollerController = + mock(NotificationStackScrollLayoutController.class); private final NotificationPanelViewController mPanelView = mock(NotificationPanelViewController.class); private final DarkIconDispatcher mDarkIconDispatcher = mock(DarkIconDispatcher.class); @@ -93,9 +93,9 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mWakeUpCoordinator, mKeyguardStateController, mCommandQueue, - mHeadsUpStatusBarView, - mStackScroller, + mStackScrollerController, mPanelView, + mHeadsUpStatusBarView, new View(mContext), mOperatorNameView, new View(mContext)); @@ -172,9 +172,9 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mWakeUpCoordinator, mKeyguardStateController, mCommandQueue, - mHeadsUpStatusBarView, - mStackScroller, + mStackScrollerController, mPanelView, + mHeadsUpStatusBarView, new View(mContext), new View(mContext), new View(mContext)); @@ -193,14 +193,14 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { reset(mHeadsUpManager); reset(mDarkIconDispatcher); reset(mPanelView); - reset(mStackScroller); + reset(mStackScrollerController); mHeadsUpAppearanceController.destroy(); verify(mHeadsUpManager).removeListener(any()); verify(mDarkIconDispatcher).removeDarkReceiver((DarkIconDispatcher.DarkReceiver) any()); verify(mPanelView).removeVerticalTranslationListener(any()); verify(mPanelView).removeTrackingHeadsUpListener(any()); verify(mPanelView).setHeadsUpAppearanceController(any()); - verify(mStackScroller).removeOnExpandedHeightChangedListener(any()); - verify(mStackScroller).removeOnLayoutChangeListener(any()); + verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any()); + verify(mStackScrollerController).removeOnLayoutChangeListener(any()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index c7434f6fd95f..a0c0e7979084 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -63,7 +63,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -74,6 +74,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.ZenModeController; @@ -115,7 +116,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private HeadsUpManagerPhone mHeadsUpManager; @Mock - private NotificationShelf mNotificationShelf; + private NotificationShelfController mNotificationShelfController; @Mock private NotificationGroupManager mGroupManager; @Mock @@ -186,7 +187,8 @@ public class NotificationPanelViewTest extends SysuiTestCase { private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController; - private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder; + @Mock + private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; private NotificationPanelViewController mNotificationPanelViewController; private View.AccessibilityDelegate mAccessibiltyDelegate; @@ -205,14 +207,18 @@ public class NotificationPanelViewTest extends SysuiTestCase { when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch); when(mView.findViewById(R.id.notification_stack_scroller)) .thenReturn(mNotificationStackScrollLayout); - when(mNotificationStackScrollLayout.getHeight()).thenReturn(1000); - when(mNotificationStackScrollLayout.getHeadsUpCallback()).thenReturn(mHeadsUpCallback); + when(mNotificationStackScrollLayout.getController()) + .thenReturn(mNotificationStackScrollLayoutController); + when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000); + when(mNotificationStackScrollLayoutController.getHeadsUpCallback()) + .thenReturn(mHeadsUpCallback); when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea); when(mKeyguardBottomArea.getLeftView()).thenReturn(mock(KeyguardAffordanceView.class)); when(mKeyguardBottomArea.getRightView()).thenReturn(mock(KeyguardAffordanceView.class)); when(mView.findViewById(R.id.big_clock_container)).thenReturn(mBigClockContainer); when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame); - mFlingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(mDisplayMetrics); + FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder( + mDisplayMetrics); doAnswer((Answer<Void>) invocation -> { mTouchHandler = invocation.getArgument(0); @@ -241,19 +247,19 @@ public class NotificationPanelViewTest extends SysuiTestCase { mDozeParameters, mCommandQueue, mVibratorHelper, mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor, mMetricsLogger, mActivityManager, mZenModeController, mConfigurationController, - mFlingAnimationUtilsBuilder, mStatusBarTouchableRegionManager, + flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager, mConversationNotificationManager, mMediaHiearchyManager, mBiometricUnlockController, mStatusBarKeyguardViewManager, - () -> mKeyguardClockSwitchController); + () -> mKeyguardClockSwitchController, + mNotificationStackScrollLayoutController); mNotificationPanelViewController.initDependencies(mStatusBar, mGroupManager, - mNotificationShelf, mNotificationAreaController, mScrimController); + mNotificationShelfController, mNotificationAreaController, mScrimController); mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); mNotificationPanelViewController.setBar(mPanelBar); ArgumentCaptor<View.AccessibilityDelegate> accessibilityDelegateArgumentCaptor = ArgumentCaptor.forClass(View.AccessibilityDelegate.class); - verify(mView) - .setAccessibilityDelegate(accessibilityDelegateArgumentCaptor.capture()); + verify(mView).setAccessibilityDelegate(accessibilityDelegateArgumentCaptor.capture()); mAccessibiltyDelegate = accessibilityDelegateArgumentCaptor.getValue(); } @@ -261,8 +267,10 @@ public class NotificationPanelViewTest extends SysuiTestCase { public void testSetDozing_notifiesNsslAndStateController() { mNotificationPanelViewController.setDozing(true /* dozing */, true /* animate */, null /* touch */); - InOrder inOrder = inOrder(mNotificationStackScrollLayout, mStatusBarStateController); - inOrder.verify(mNotificationStackScrollLayout).setDozing(eq(true), eq(true), eq(null)); + InOrder inOrder = inOrder( + mNotificationStackScrollLayoutController, mStatusBarStateController); + inOrder.verify(mNotificationStackScrollLayoutController) + .setDozing(eq(true), eq(true), eq(null)); inOrder.verify(mStatusBarStateController).setDozeAmount(eq(1f), eq(true)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java index e04d25b17c71..51900cb7dda1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java @@ -100,7 +100,9 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { mController = new NotificationShadeWindowViewController( new InjectionInflationController( - SystemUIFactory.getInstance().getRootComponent()), + SystemUIFactory.getInstance() + .getRootComponent() + .createViewInstanceCreatorFactory()), mCoordinator, mPulseExpansionHandler, mDynamicPrivacyController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index 318e9b87fa70..e4f481241257 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -23,13 +23,11 @@ import static org.mockito.Mockito.when; import android.app.Notification; import android.app.StatusBarManager; -import android.content.Context; import android.metrics.LogMaker; import android.support.test.metricshelper.MetricsAsserts; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; -import android.view.ViewGroup; import androidx.test.filters.SmallTest; @@ -59,6 +57,8 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; @@ -112,11 +112,17 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { NotificationShadeWindowView notificationShadeWindowView = mock(NotificationShadeWindowView.class); + NotificationStackScrollLayoutController stackScrollLayoutController = + mock(NotificationStackScrollLayoutController.class); + when(stackScrollLayoutController.getView()).thenReturn( + mock(NotificationStackScrollLayout.class)); + when(stackScrollLayoutController.getNotificationListContainer()).thenReturn( + mock(NotificationListContainer.class)); when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources()); mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(mContext, mock(NotificationPanelViewController.class), mock(HeadsUpManagerPhone.class), - notificationShadeWindowView, mock(NotificationListContainerViewGroup.class), + notificationShadeWindowView, stackScrollLayoutController, mock(DozeScrimController.class), mock(ScrimController.class), mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class), mock(KeyguardStateController.class), @@ -205,14 +211,4 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { new LogMaker(MetricsEvent.ACTION_LS_NOTE) .setType(MetricsEvent.TYPE_ACTION)); } - - // We need this because mockito doesn't know how to construct a mock that extends ViewGroup - // and implements NotificationListContainer without it because of classloader issues. - private abstract static class NotificationListContainerViewGroup extends ViewGroup - implements NotificationListContainer { - - public NotificationListContainerViewGroup(Context context) { - super(context); - } - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 5a08c9ca017b..a385d81331ed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -124,7 +124,9 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -171,6 +173,8 @@ public class StatusBarTest extends SysuiTestCase { @Mock private KeyguardStateController mKeyguardStateController; @Mock private KeyguardIndicationController mKeyguardIndicationController; @Mock private NotificationStackScrollLayout mStackScroller; + @Mock private NotificationStackScrollLayoutController mStackScrollerController; + @Mock private NotificationListContainer mNotificationListContainer; @Mock private HeadsUpManagerPhone mHeadsUpManager; @Mock private NotificationPanelViewController mNotificationPanelViewController; @Mock private NotificationPanelView mNotificationPanelView; @@ -283,6 +287,10 @@ public class StatusBarTest extends SysuiTestCase { mContext.setTheme(R.style.Theme_SystemUI_Light); + when(mStackScroller.getController()).thenReturn(mStackScrollerController); + when(mStackScrollerController.getView()).thenReturn(mStackScroller); + when(mStackScrollerController.getNotificationListContainer()).thenReturn( + mNotificationListContainer); when(mStackScroller.generateLayoutParams(any())).thenReturn(new LayoutParams(0, 0)); when(mNotificationPanelViewController.getView()).thenReturn(mNotificationPanelView); when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0)); @@ -429,7 +437,7 @@ public class StatusBarTest extends SysuiTestCase { mStatusBar.mStackScroller = mStackScroller; mStatusBar.startKeyguard(); mInitController.executePostInitTasks(); - notificationLogger.setUpWithContainer(mStackScroller); + notificationLogger.setUpWithContainer(mNotificationListContainer); } @Test diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index 4b6bbac051e0..75c819bb0ced 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt @@ -18,33 +18,40 @@ package com.android.networkstack.tethering import android.app.Notification import android.app.NotificationManager +import android.app.PendingIntent +import android.app.PendingIntent.FLAG_IMMUTABLE import android.content.Context +import android.content.Intent import android.content.pm.ActivityInfo import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.content.res.Resources import android.net.ConnectivityManager.TETHERING_WIFI +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING import android.os.Handler import android.os.HandlerThread import android.os.Looper -import android.net.NetworkCapabilities -import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING import android.os.UserHandle +import android.provider.Settings import android.telephony.TelephonyManager import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.test.BroadcastInterceptingContext +import com.android.networkstack.tethering.TetheringNotificationUpdater.ACTION_DISABLE_TETHERING import com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE import com.android.networkstack.tethering.TetheringNotificationUpdater.EVENT_SHOW_NO_UPSTREAM import com.android.networkstack.tethering.TetheringNotificationUpdater.NO_UPSTREAM_NOTIFICATION_ID import com.android.networkstack.tethering.TetheringNotificationUpdater.RESTRICTED_NOTIFICATION_ID import com.android.networkstack.tethering.TetheringNotificationUpdater.ROAMING_NOTIFICATION_ID import com.android.networkstack.tethering.TetheringNotificationUpdater.VERIZON_CARRIER_ID +import com.android.networkstack.tethering.TetheringNotificationUpdater.getSettingsPackageName import com.android.testutils.waitForIdle import org.junit.After import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull import org.junit.Assert.fail import org.junit.Before import org.junit.Test @@ -87,12 +94,17 @@ class TetheringNotificationUpdaterTest { // every test but should always be initialized before use (or the test should crash). private lateinit var context: TestContext private lateinit var notificationUpdater: TetheringNotificationUpdater + + // Initializing the following members depends on initializing some of the mocks and + // is more logically done in setup(). private lateinit var fakeTetheringThread: HandlerThread private val ROAMING_CAPABILITIES = NetworkCapabilities() private val HOME_CAPABILITIES = NetworkCapabilities().addCapability(NET_CAPABILITY_NOT_ROAMING) private val NOTIFICATION_ICON_ID = R.drawable.stat_sys_tether_general private val TIMEOUT_MS = 500L + private val ACTIVITY_PENDING_INTENT = 0 + private val BROADCAST_PENDING_INTENT = 1 private inner class TestContext(c: Context) : BroadcastInterceptingContext(c) { override fun createContextAsUser(user: UserHandle, flags: Int) = @@ -146,10 +158,43 @@ class TetheringNotificationUpdaterTest { fakeTetheringThread.quitSafely() } + private fun verifyActivityPendingIntent(intent: Intent, flags: Int) { + // Use FLAG_NO_CREATE to verify whether PendingIntent has FLAG_IMMUTABLE flag(forcefully add + // the flag in creating arguments). If the described PendingIntent does not already exist, + // getActivity() will return null instead of PendingIntent object. + val pi = PendingIntent.getActivity( + context.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), + 0 /* requestCode */, + intent, + flags or FLAG_IMMUTABLE or PendingIntent.FLAG_NO_CREATE, + null /* options */) + assertNotNull("Activity PendingIntent with FLAG_IMMUTABLE does not exist.", pi) + } + + private fun verifyBroadcastPendingIntent(intent: Intent, flags: Int) { + // Use FLAG_NO_CREATE to verify whether PendingIntent has FLAG_IMMUTABLE flag(forcefully add + // the flag in creating arguments). If the described PendingIntent does not already exist, + // getBroadcast() will return null instead of PendingIntent object. + val pi = PendingIntent.getBroadcast( + context.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), + 0 /* requestCode */, + intent, + flags or FLAG_IMMUTABLE or PendingIntent.FLAG_NO_CREATE) + assertNotNull("Broadcast PendingIntent with FLAG_IMMUTABLE does not exist.", pi) + } + private fun Notification.title() = this.extras.getString(Notification.EXTRA_TITLE) private fun Notification.text() = this.extras.getString(Notification.EXTRA_TEXT) - private fun verifyNotification(iconId: Int, title: String, text: String, id: Int) { + private fun verifyNotification( + iconId: Int, + title: String, + text: String, + id: Int, + intentSenderType: Int, + intent: Intent, + flags: Int + ) { verify(notificationManager, never()).cancel(any(), eq(id)) val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java) @@ -161,6 +206,11 @@ class TetheringNotificationUpdaterTest { assertEquals(title, notification.title()) assertEquals(text, notification.text()) + when (intentSenderType) { + ACTIVITY_PENDING_INTENT -> verifyActivityPendingIntent(intent, flags) + BROADCAST_PENDING_INTENT -> verifyBroadcastPendingIntent(intent, flags) + } + reset(notificationManager) } @@ -176,6 +226,10 @@ class TetheringNotificationUpdaterTest { @Test fun testRestrictedNotification() { + val settingsIntent = Intent(Settings.ACTION_TETHER_SETTINGS) + .setPackage(getSettingsPackageName(context.packageManager)) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + // Set test sub id. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) @@ -183,7 +237,7 @@ class TetheringNotificationUpdaterTest { // User restrictions on. Show restricted notification. notificationUpdater.notifyTetheringDisabledByRestriction() verifyNotification(NOTIFICATION_ICON_ID, TEST_DISALLOW_TITLE, TEST_DISALLOW_MESSAGE, - RESTRICTED_NOTIFICATION_ID) + RESTRICTED_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE) // User restrictions off. Clear notification. notificationUpdater.tetheringRestrictionLifted() @@ -196,7 +250,7 @@ class TetheringNotificationUpdaterTest { // User restrictions on again. Show restricted notification. notificationUpdater.notifyTetheringDisabledByRestriction() verifyNotification(NOTIFICATION_ICON_ID, TEST_DISALLOW_TITLE, TEST_DISALLOW_MESSAGE, - RESTRICTED_NOTIFICATION_ID) + RESTRICTED_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE) } val MAX_BACKOFF_MS = 200L @@ -234,6 +288,8 @@ class TetheringNotificationUpdaterTest { @Test fun testNoUpstreamNotification() { + val disableIntent = Intent(ACTION_DISABLE_TETHERING).setPackage(context.packageName) + // Set test sub id. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) @@ -246,7 +302,8 @@ class TetheringNotificationUpdaterTest { notificationUpdater.onUpstreamCapabilitiesChanged(null) notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, - NO_UPSTREAM_NOTIFICATION_ID) + NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent, + FLAG_IMMUTABLE) // Same capabilities changed. Nothing happened. notificationUpdater.onUpstreamCapabilitiesChanged(null) @@ -260,7 +317,8 @@ class TetheringNotificationUpdaterTest { notificationUpdater.onUpstreamCapabilitiesChanged(null) notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, - NO_UPSTREAM_NOTIFICATION_ID) + NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent, + FLAG_IMMUTABLE) // No downstream. notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) @@ -305,6 +363,11 @@ class TetheringNotificationUpdaterTest { @Test fun testRoamingNotification() { + val disableIntent = Intent(ACTION_DISABLE_TETHERING).setPackage(context.packageName) + val settingsIntent = Intent(Settings.ACTION_TETHER_SETTINGS) + .setPackage(getSettingsPackageName(context.packageManager)) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + // Set test sub id. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) @@ -316,7 +379,7 @@ class TetheringNotificationUpdaterTest { // Upstream capabilities changed to roaming state. Show roaming notification. notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) verifyNotification(NOTIFICATION_ICON_ID, TEST_ROAMING_TITLE, TEST_ROAMING_MESSAGE, - ROAMING_NOTIFICATION_ID) + ROAMING_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE) // Same capabilities change. Nothing happened. notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) @@ -329,14 +392,15 @@ class TetheringNotificationUpdaterTest { // Upstream capabilities changed to roaming state again. Show roaming notification. notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) verifyNotification(NOTIFICATION_ICON_ID, TEST_ROAMING_TITLE, TEST_ROAMING_MESSAGE, - ROAMING_NOTIFICATION_ID) + ROAMING_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE) // No upstream. Clear roaming notification and show no upstream notification. notificationUpdater.onUpstreamCapabilitiesChanged(null) notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) verifyNotificationCancelled(listOf(ROAMING_NOTIFICATION_ID), false) verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, - NO_UPSTREAM_NOTIFICATION_ID) + NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent, + FLAG_IMMUTABLE) // No downstream. notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) @@ -347,7 +411,8 @@ class TetheringNotificationUpdaterTest { notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) verifyNotificationCancelled(listOf(ROAMING_NOTIFICATION_ID), false) verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, - NO_UPSTREAM_NOTIFICATION_ID) + NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent, + FLAG_IMMUTABLE) // Set R.bool.config_upstream_roaming_notification to false and change upstream // network to roaming state again. No roaming notification. @@ -363,8 +428,7 @@ class TetheringNotificationUpdaterTest { val testSettingsPackageName = "com.android.test.settings" val pm = mock(PackageManager::class.java) doReturn(null).`when`(pm).resolveActivity(any(), anyInt()) - assertEquals(defaultSettingsPackageName, - TetheringNotificationUpdater.getSettingsPackageName(pm)) + assertEquals(defaultSettingsPackageName, getSettingsPackageName(pm)) val resolveInfo = ResolveInfo().apply { activityInfo = ActivityInfo().apply { @@ -375,7 +439,6 @@ class TetheringNotificationUpdaterTest { } } doReturn(resolveInfo).`when`(pm).resolveActivity(any(), anyInt()) - assertEquals(testSettingsPackageName, - TetheringNotificationUpdater.getSettingsPackageName(pm)) + assertEquals(testSettingsPackageName, getSettingsPackageName(pm)) } } diff --git a/services/Android.bp b/services/Android.bp index ef52c2aff002..b348b91a1bd7 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -156,14 +156,10 @@ droidstubs { java_library { name: "android_system_server_stubs_current", - defaults: ["android_stubs_dists_default"], srcs: [":services-stubs.sources"], installable: false, static_libs: ["android_module_lib_stubs_current"], sdk_version: "none", system_modules: "none", java_version: "1.8", - dist: { - dir: "apistubs/android/system-server", - }, } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index e1baefed4425..a2d58c8019fc 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -609,6 +609,9 @@ public class TouchExplorer extends BaseEventStreamTransformation mSendHoverExitDelayed.cancel(); if (mGestureDetector.isMultiFingerGesturesEnabled() && mGestureDetector.isTwoFingerPassthroughEnabled()) { + if (pointerIndex < 0) { + return; + } final float deltaX = mReceivedPointerTracker.getReceivedPointerDownX(pointerId) - rawEvent.getX(pointerIndex); @@ -628,7 +631,7 @@ public class TouchExplorer extends BaseEventStreamTransformation // Two pointers moving in the same direction within // a given distance perform a drag. mState.startDragging(); - adjustEventLocationForDrag(event); + computeDraggingPointerIdIfNeeded(event); pointerIdBits = 1 << mDraggingPointerId; event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags()); mDispatcher.sendMotionEvent( @@ -791,7 +794,7 @@ public class TouchExplorer extends BaseEventStreamTransformation case 2: if (isDraggingGesture(event)) { // If still dragging send a drag event. - adjustEventLocationForDrag(event); + computeDraggingPointerIdIfNeeded(event); mDispatcher.sendMotionEvent( event, ACTION_MOVE, rawEvent, pointerIdBits, policyFlags); } else { @@ -956,37 +959,27 @@ public class TouchExplorer extends BaseEventStreamTransformation } /** - * Adjust the location of an injected event when performing a drag. The location will be the - * location of the finger closest to an edge of the screen. + * Computes {@link #mDraggingPointerId} if it is invalid. The pointer will be the finger + * closet to an edge of the screen. */ - private void adjustEventLocationForDrag(MotionEvent event) { + private void computeDraggingPointerIdIfNeeded(MotionEvent event) { + if (mDraggingPointerId != INVALID_POINTER_ID) { + // If we have a valid pointer ID, we should be good + final int pointerIndex = event.findPointerIndex(mDraggingPointerId); + if (event.findPointerIndex(pointerIndex) >= 0) { + return; + } + } + // Use the pointer that is closest to its closest edge. final float firstPtrX = event.getX(0); final float firstPtrY = event.getY(0); final int firstPtrId = event.getPointerId(0); final float secondPtrX = event.getX(1); final float secondPtrY = event.getY(1); final int secondPtrId = event.getPointerId(1); - float draggingX; - float draggingY; - if (mDraggingPointerId == INVALID_POINTER_ID) { - // The goal is to use the coordinates of the finger that is closest to its closest edge. - if (getDistanceToClosestEdge(firstPtrX, firstPtrY) - < getDistanceToClosestEdge(secondPtrX, secondPtrY)) { - draggingX = firstPtrX; - draggingY = firstPtrY; - mDraggingPointerId = firstPtrId; - } else { - draggingX = secondPtrX; - draggingY = secondPtrY; - mDraggingPointerId = secondPtrId; - } - } else { - // Just use the coordinates of the dragging pointer. - int pointerIndex = event.findPointerIndex(mDraggingPointerId); - draggingX = event.getX(pointerIndex); - draggingY = event.getY(pointerIndex); - } - event.setLocation(draggingX, draggingY); + mDraggingPointerId = (getDistanceToClosestEdge(firstPtrX, firstPtrY) + < getDistanceToClosestEdge(secondPtrX, secondPtrY)) + ? firstPtrId : secondPtrId; } private float getDistanceToClosestEdge(float x, float y) { diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java index bd25f2bea881..3ee5b28ee338 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java @@ -25,10 +25,12 @@ import static java.util.Arrays.copyOfRange; import android.annotation.Nullable; import android.content.Context; +import android.graphics.Point; import android.provider.Settings; import android.util.Log; import android.util.MathUtils; import android.util.Slog; +import android.view.Display; import android.view.MotionEvent; import com.android.internal.annotations.VisibleForTesting; @@ -90,6 +92,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate; private final int mDisplayId; + private final Context mContext; + private final Point mTempPoint = new Point(); private final Queue<MotionEvent> mDebugOutputEventHistory; @@ -107,7 +111,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl Slog.i(LOG_TAG, "WindowMagnificationGestureHandler() , displayId = " + displayId + ")"); } - + mContext = context; mWindowMagnificationMgr = windowMagnificationMgr; mDetectShortcutTrigger = detectShortcutTrigger; mDisplayId = displayId; @@ -184,7 +188,14 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl if (!mDetectShortcutTrigger) { return; } - toggleMagnification(Float.NaN, Float.NaN); + final Point screenSize = mTempPoint; + getScreenSize(mTempPoint); + toggleMagnification(screenSize.x / 2.0f, screenSize.y / 2.0f); + } + + private void getScreenSize(Point outSize) { + final Display display = mContext.getDisplay(); + display.getRealSize(outSize); } @Override diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index 1c3116699b2d..a92d334a94fa 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -27,6 +27,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.drawable.Drawable; @@ -214,7 +215,13 @@ final class SaveUi { return componentName; } intent.addFlags(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL); - return intent.resolveActivity(packageManager); + final ActivityInfo ai = + intent.resolveActivityInfo(packageManager, PackageManager.MATCH_INSTANT); + if (ai != null) { + return new ComponentName(ai.applicationInfo.packageName, ai.name); + } + + return null; } }; final LayoutInflater inflater = LayoutInflater.from(context); diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 29235dd1ee72..e68c07ed73f7 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -441,6 +441,7 @@ public class UserBackupManagerService { private long mAncestralToken = 0; private long mCurrentToken = 0; @Nullable private File mAncestralSerialNumberFile; + @OperationType private volatile long mAncestralOperationType; private final ContentObserver mSetupObserver; private final BroadcastReceiver mRunInitReceiver; @@ -881,6 +882,10 @@ public class UserBackupManagerService { mAncestralToken = ancestralToken; } + public void setAncestralOperationType(@OperationType int operationType) { + mAncestralOperationType = operationType; + } + public long getCurrentToken() { return mCurrentToken; } @@ -1808,6 +1813,16 @@ public class UserBackupManagerService { } } + private BackupEligibilityRules getEligibilityRulesForRestoreAtInstall(long restoreToken) { + if (mAncestralOperationType == OperationType.MIGRATION && restoreToken == mAncestralToken) { + return getEligibilityRulesForOperation(OperationType.MIGRATION); + } else { + // If we're not using the ancestral data set, it means we're restoring from a backup + // that happened on this device. + return mScheduledBackupEligibility; + } + } + /** * Get the restore-set token for the best-available restore set for this {@code packageName}: * the active set if possible, else the ancestral one. Returns zero if none available. @@ -3976,7 +3991,7 @@ public class UserBackupManagerService { packageName, token, listener, - mScheduledBackupEligibility); + getEligibilityRulesForRestoreAtInstall(restoreSet)); mBackupHandler.sendMessage(msg); } catch (Exception e) { // Calling into the transport broke; back off and proceed with the installation. diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index 622067999f27..b9625397d237 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -27,6 +27,7 @@ import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERA import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; +import android.app.backup.BackupManager; import android.app.backup.FullBackup; import android.app.backup.IBackupManagerMonitor; import android.app.backup.IFullBackupRestoreObserver; @@ -633,7 +634,11 @@ public class FullRestoreEngine extends RestoreEngine { setRunning(false); } - private static boolean isRestorableFile(FileMetadata info) { + private boolean isRestorableFile(FileMetadata info) { + if (mBackupEligibilityRules.getOperationType() == BackupManager.OperationType.MIGRATION) { + // Everything is eligible for device-to-device migration. + return true; + } if (FullBackup.CACHE_TREE_TOKEN.equals(info.domain)) { if (MORE_DEBUG) { Slog.i(TAG, "Dropping cache file path " + info.path); diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 7baf55992770..abf11bd542a1 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -1136,6 +1136,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { if (mIsSystemRestore && mPmAgent != null) { backupManagerService.setAncestralPackages(mPmAgent.getRestoredPackages()); backupManagerService.setAncestralToken(mToken); + backupManagerService.setAncestralOperationType( + mBackupEligibilityRules.getOperationType()); backupManagerService.writeRestoreTokens(); } diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java index d6598975a647..73ba1f19c092 100644 --- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java +++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java @@ -85,12 +85,15 @@ public class BackupEligibilityRules { * <li>they run as a system-level uid but do not supply their own backup agent * <li>it is the special shared-storage backup package used for 'adb backup' * </ol> + * + * However, the above eligibility rules are ignored for non-system apps in in case of + * device-to-device migration, see {@link OperationType}. */ @VisibleForTesting public boolean appIsEligibleForBackup(ApplicationInfo app) { - // 1. their manifest states android:allowBackup="false" - boolean appAllowsBackup = (app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0; - if (!appAllowsBackup && !forceFullBackup(app.uid, mOperationType)) { + // 1. their manifest states android:allowBackup="false" and this is not a device-to-device + // migration + if (!isAppBackupAllowed(app)) { return false; } @@ -123,6 +126,23 @@ public class BackupEligibilityRules { } /** + * Check if this app allows backup. Apps can opt out of backup by stating + * android:allowBackup="false" in their manifest. However, this flag is ignored for non-system + * apps during device-to-device migrations, see {@link OperationType}. + * + * @param app The app under check. + * @return boolean indicating whether backup is allowed. + */ + public boolean isAppBackupAllowed(ApplicationInfo app) { + if (mOperationType == OperationType.MIGRATION && !UserHandle.isCore(app.uid)) { + // Backup / restore of all apps is force allowed during device-to-device migration. + return true; + } + + return (app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0; + } + + /** * Returns whether an app is eligible for backup at runtime. That is, the app has to: * <ol> * <li>Return true for {@link #appIsEligibleForBackup(ApplicationInfo, int)} diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java index bf8e9c8512ae..3789fa14e87b 100644 --- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java +++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java @@ -402,7 +402,7 @@ public class TarBackupReader { info.packageName, PackageManager.GET_SIGNING_CERTIFICATES, userId); // Fall through to IGNORE if the app explicitly disallows backup final int flags = pkgInfo.applicationInfo.flags; - if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { + if (eligibilityRules.isAppBackupAllowed(pkgInfo.applicationInfo)) { // Restore system-uid-space packages only if they have // defined a custom backup agent if (!UserHandle.isCore(pkgInfo.applicationInfo.uid) diff --git a/services/core/Android.bp b/services/core/Android.bp index e76ec743661c..addaa6568665 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -2,38 +2,25 @@ filegroup { name: "services.core-sources", srcs: ["java/**/*.java"], path: "java", - visibility: ["//frameworks/base/services"], -} - -java_library { - name: "protolog-common", - srcs: [ - "java/com/android/server/protolog/common/**/*.java", - ], - host_supported: true, -} - -java_library { - name: "services.core.wm.protologgroups", - srcs: [ - "java/com/android/server/wm/ProtoLogGroup.java", + visibility: [ + "//frameworks/base/services", + "//frameworks/base/core/java/com/android/internal/protolog", ], - static_libs: ["protolog-common"], } genrule { name: "services.core.protologsrc", srcs: [ - ":services.core.wm.protologgroups", + ":protolog-groups", ":services.core-sources", ], tools: ["protologtool"], cmd: "$(location protologtool) transform-protolog-calls " + - "--protolog-class com.android.server.protolog.common.ProtoLog " + - "--protolog-impl-class com.android.server.protolog.ProtoLogImpl " + - "--protolog-cache-class 'com.android.server.protolog.ProtoLog$$Cache' " + - "--loggroups-class com.android.server.wm.ProtoLogGroup " + - "--loggroups-jar $(location :services.core.wm.protologgroups) " + + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " + + "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " + + "--loggroups-class com.android.internal.protolog.ProtoLogGroup " + + "--loggroups-jar $(location :protolog-groups) " + "--output-srcjar $(out) " + "$(locations :services.core-sources)", out: ["services.core.protolog.srcjar"], @@ -42,14 +29,14 @@ genrule { genrule { name: "generate-protolog.json", srcs: [ - ":services.core.wm.protologgroups", + ":protolog-groups", ":services.core-sources", ], tools: ["protologtool"], cmd: "$(location protologtool) generate-viewer-config " + - "--protolog-class com.android.server.protolog.common.ProtoLog " + - "--loggroups-class com.android.server.wm.ProtoLogGroup " + - "--loggroups-jar $(location :services.core.wm.protologgroups) " + + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--loggroups-class com.android.internal.protolog.ProtoLogGroup " + + "--loggroups-jar $(location :protolog-groups) " + "--viewer-conf $(out) " + "$(locations :services.core-sources)", out: ["services.core.protolog.json"], @@ -109,6 +96,7 @@ java_library_static { ], static_libs: [ + "protolog-lib", "time_zone_distro", "time_zone_distro_installer", "android.hardware.authsecret-V1.0-java", diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index a3c04be02c6f..c9513592ea79 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -28,7 +28,9 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.BatteryStatsInternal; import android.os.Binder; +import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.ShellCommand; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; @@ -308,50 +310,134 @@ public class BinderCallsStatsService extends Binder { } boolean verbose = false; + int worksourceUid = Process.INVALID_UID; if (args != null) { - for (final String arg : args) { + for (int i = 0; i < args.length; i++) { + String arg = args[i]; if ("-a".equals(arg)) { verbose = true; - } else if ("--reset".equals(arg)) { + } else if ("-h".equals(arg)) { + pw.println("dumpsys binder_calls_stats options:"); + pw.println(" -a: Verbose"); + pw.println(" --work-source-uid <UID>: Dump binder calls from the UID"); + return; + } else if ("--work-source-uid".equals(arg)) { + i++; + if (i >= args.length) { + throw new IllegalArgumentException( + "Argument expected after \"" + arg + "\""); + } + String uidArg = args[i]; + try { + worksourceUid = Integer.parseInt(uidArg); + } catch (NumberFormatException e) { + pw.println("Invalid UID: " + uidArg); + return; + } + } + } + + if (args.length > 0 && worksourceUid == Process.INVALID_UID) { + // For compatibility, support "cmd"-style commands when passed to "dumpsys". + BinderCallsStatsShellCommand command = new BinderCallsStatsShellCommand(pw); + int status = command.exec(this, null, FileDescriptor.out, FileDescriptor.err, args); + if (status == 0) { + return; + } + } + } + mBinderCallsStats.dump(pw, AppIdToPackageMap.getSnapshot(), worksourceUid, verbose); + } + + @Override + public int handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out, + ParcelFileDescriptor err, String[] args) { + ShellCommand command = new BinderCallsStatsShellCommand(null); + int status = command.exec(this, in.getFileDescriptor(), out.getFileDescriptor(), + err.getFileDescriptor(), args); + if (status != 0) { + command.onHelp(); + } + return status; + } + + private class BinderCallsStatsShellCommand extends ShellCommand { + private final PrintWriter mPrintWriter; + + BinderCallsStatsShellCommand(PrintWriter printWriter) { + mPrintWriter = printWriter; + } + + @Override + public PrintWriter getOutPrintWriter() { + if (mPrintWriter != null) { + return mPrintWriter; + } + return super.getOutPrintWriter(); + } + + @Override + public int onCommand(String cmd) { + PrintWriter pw = getOutPrintWriter(); + if (cmd == null) { + return -1; + } + + switch (cmd) { + case "--reset": reset(); pw.println("binder_calls_stats reset."); - return; - } else if ("--enable".equals(arg)) { + break; + case "--enable": Binder.setObserver(mBinderCallsStats); - return; - } else if ("--disable".equals(arg)) { + break; + case "--disable": Binder.setObserver(null); - return; - } else if ("--no-sampling".equals(arg)) { + break; + case "--no-sampling": mBinderCallsStats.setSamplingInterval(1); - return; - } else if ("--enable-detailed-tracking".equals(arg)) { + break; + case "--enable-detailed-tracking": SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, "1"); mBinderCallsStats.setDetailedTracking(true); pw.println("Detailed tracking enabled"); - return; - } else if ("--disable-detailed-tracking".equals(arg)) { + break; + case "--disable-detailed-tracking": SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, ""); mBinderCallsStats.setDetailedTracking(false); pw.println("Detailed tracking disabled"); - return; - } else if ("--dump-worksource-provider".equals(arg)) { + break; + case "--dump-worksource-provider": + mBinderCallsStats.setDetailedTracking(true); mWorkSourceProvider.dump(pw, AppIdToPackageMap.getSnapshot()); - return; - } else if ("-h".equals(arg)) { - pw.println("binder_calls_stats commands:"); - pw.println(" --reset: Reset stats"); - pw.println(" --enable: Enable tracking binder calls"); - pw.println(" --disable: Disables tracking binder calls"); - pw.println(" --no-sampling: Tracks all calls"); - pw.println(" --enable-detailed-tracking: Enables detailed tracking"); - pw.println(" --disable-detailed-tracking: Disables detailed tracking"); - return; - } else { - pw.println("Unknown option: " + arg); - } + break; + case "--work-source-uid": + String uidArg = getNextArgRequired(); + try { + int uid = Integer.parseInt(uidArg); + mBinderCallsStats.recordAllCallsForWorkSourceUid(uid); + } catch (NumberFormatException e) { + pw.println("Invalid UID: " + uidArg); + return -1; + } + break; + default: + return handleDefaultCommands(cmd); } + return 0; + } + + @Override + public void onHelp() { + PrintWriter pw = getOutPrintWriter(); + pw.println("binder_calls_stats commands:"); + pw.println(" --reset: Reset stats"); + pw.println(" --enable: Enable tracking binder calls"); + pw.println(" --disable: Disables tracking binder calls"); + pw.println(" --no-sampling: Tracks all calls"); + pw.println(" --enable-detailed-tracking: Enables detailed tracking"); + pw.println(" --disable-detailed-tracking: Disables detailed tracking"); + pw.println(" --work-source-uid <UID>: Track all binder calls from the UID"); } - mBinderCallsStats.dump(pw, AppIdToPackageMap.getSnapshot(), verbose); } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ef62a991f323..bd590d317910 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4966,7 +4966,7 @@ public class ConnectivityService extends IConnectivityManager.Stub Slog.w(TAG, "User " + userId + " has no Vpn configuration"); return null; } - return vpn.getLockdownWhitelist(); + return vpn.getLockdownAllowlist(); } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 6402e07bddc3..b2f0c8376db1 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1477,7 +1477,7 @@ public class IpSecService extends IIpSecService.Stub { } /** - * Checks an IpSecConfig parcel to ensure that the contents are sane and throws an + * Checks an IpSecConfig parcel to ensure that the contents are valid and throws an * IllegalArgumentException if they are not. */ private void checkIpSecConfig(IpSecConfig config) { diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 0ddfa1c16a0a..97f3b373f63e 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -185,10 +185,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub { /** Set of interfaces with active alerts. */ @GuardedBy("mQuotaLock") private HashMap<String, Long> mActiveAlerts = Maps.newHashMap(); - /** Set of UIDs blacklisted on metered networks. */ + /** Set of UIDs denylisted on metered networks. */ @GuardedBy("mRulesLock") private SparseBooleanArray mUidRejectOnMetered = new SparseBooleanArray(); - /** Set of UIDs whitelisted on metered networks. */ + /** Set of UIDs allowlisted on metered networks. */ @GuardedBy("mRulesLock") private SparseBooleanArray mUidAllowOnMetered = new SparseBooleanArray(); /** Set of UIDs with cleartext penalties. */ @@ -561,27 +561,27 @@ public class NetworkManagementService extends INetworkManagementService.Stub { synchronized (mRulesLock) { size = mUidRejectOnMetered.size(); if (size > 0) { - if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered blacklist rules"); + if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered denylist rules"); uidRejectOnQuota = mUidRejectOnMetered; mUidRejectOnMetered = new SparseBooleanArray(); } size = mUidAllowOnMetered.size(); if (size > 0) { - if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered whitelist rules"); + if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered allowlist rules"); uidAcceptOnQuota = mUidAllowOnMetered; mUidAllowOnMetered = new SparseBooleanArray(); } } if (uidRejectOnQuota != null) { for (int i = 0; i < uidRejectOnQuota.size(); i++) { - setUidMeteredNetworkBlacklist(uidRejectOnQuota.keyAt(i), + setUidMeteredNetworkDenylist(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i)); } } if (uidAcceptOnQuota != null) { for (int i = 0; i < uidAcceptOnQuota.size(); i++) { - setUidMeteredNetworkWhitelist(uidAcceptOnQuota.keyAt(i), + setUidMeteredNetworkAllowlist(uidAcceptOnQuota.keyAt(i), uidAcceptOnQuota.valueAt(i)); } } @@ -1307,14 +1307,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } } - private void setUidOnMeteredNetworkList(int uid, boolean blacklist, boolean enable) { + private void setUidOnMeteredNetworkList(int uid, boolean denylist, boolean enable) { NetworkStack.checkNetworkStackPermission(mContext); synchronized (mQuotaLock) { boolean oldEnable; SparseBooleanArray quotaList; synchronized (mRulesLock) { - quotaList = blacklist ? mUidRejectOnMetered : mUidAllowOnMetered; + quotaList = denylist ? mUidRejectOnMetered : mUidAllowOnMetered; oldEnable = quotaList.get(uid, false); } if (oldEnable == enable) { @@ -1324,7 +1324,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "inetd bandwidth"); try { - if (blacklist) { + if (denylist) { if (enable) { mNetdService.bandwidthAddNaughtyApp(uid); } else { @@ -1353,12 +1353,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } @Override - public void setUidMeteredNetworkBlacklist(int uid, boolean enable) { + public void setUidMeteredNetworkDenylist(int uid, boolean enable) { setUidOnMeteredNetworkList(uid, true, enable); } @Override - public void setUidMeteredNetworkWhitelist(int uid, boolean enable) { + public void setUidMeteredNetworkAllowlist(int uid, boolean enable) { setUidOnMeteredNetworkList(uid, false, enable); } @@ -1626,7 +1626,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } } } - // Normally, whitelist chains only contain deny rules, so numUids == exemptUids.length. + // Normally, allowlist chains only contain deny rules, so numUids == exemptUids.length. // But the code does not guarantee this in any way, and at least in one case - if we add // a UID rule to the firewall, and then disable the firewall - the chains can contain // the wrong type of rule. In this case, don't close connections that we shouldn't. @@ -1691,7 +1691,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { // Close any sockets that were opened by the affected UIDs. This has to be done after // disabling network connectivity, in case they react to the socket close by reopening // the connection and race with the iptables commands that enable the firewall. All - // whitelist and blacklist chains allow RSTs through. + // allowlist and denylist chains allow RSTs through. if (enable) { closeSocketsForFirewallChainLocked(chain, chainName); } @@ -1828,7 +1828,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } else { ruleName = "deny"; } - } else { // Blacklist mode + } else { // Denylist mode if (rule == FIREWALL_RULE_DENY) { ruleName = "deny"; } else { @@ -1913,8 +1913,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub { pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString()); pw.print("Data saver mode: "); pw.println(mDataSaverMode); synchronized (mRulesLock) { - dumpUidRuleOnQuotaLocked(pw, "blacklist", mUidRejectOnMetered); - dumpUidRuleOnQuotaLocked(pw, "whitelist", mUidAllowOnMetered); + dumpUidRuleOnQuotaLocked(pw, "denylist", mUidRejectOnMetered); + dumpUidRuleOnQuotaLocked(pw, "allowlist", mUidAllowOnMetered); } } @@ -2179,9 +2179,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } } - void setUidOnMeteredNetworkList(boolean blacklist, int uid, boolean enable) { + void setUidOnMeteredNetworkList(boolean denylist, int uid, boolean enable) { synchronized (mRulesLock) { - if (blacklist) { + if (denylist) { mUidRejectOnMetered.put(uid, enable); } else { mUidAllowOnMetered.put(uid, enable); diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index 1689656479a5..e675d8d458c7 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -1453,8 +1453,11 @@ public class PackageWatchdog { } else { mHealthCheckState = HealthCheckState.ACTIVE; } - Slog.i(TAG, "Updated health check state for package " + getName() + ": " - + toString(oldState) + " -> " + toString(mHealthCheckState)); + + if (oldState != mHealthCheckState) { + Slog.i(TAG, "Updated health check state for package " + getName() + ": " + + toString(oldState) + " -> " + toString(mHealthCheckState)); + } return mHealthCheckState; } diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 59ac09ca2f3d..32d02fb17983 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -114,9 +114,6 @@ public class VibratorService extends IVibratorService.Stub private static final VibrationAttributes DEFAULT_ATTRIBUTES = new VibrationAttributes.Builder().build(); - // If HAL supports callbacks set the timeout to ASYNC_TIMEOUT_MULTIPLIER * duration. - private static final long ASYNC_TIMEOUT_MULTIPLIER = 2; - // A mapping from the intensity adjustment to the scaling to apply, where the intensity // adjustment is defined as the delta between the default intensity level and the user selected // intensity level. It's important that we apply the scaling on the delta between the two so @@ -187,8 +184,8 @@ public class VibratorService extends IVibratorService.Stub static native int[] vibratorGetSupportedEffects(long controllerPtr); - static native long vibratorPerformEffect(long effect, long strength, Vibration vibration, - boolean withCallback); + static native long vibratorPerformEffect( + long controllerPtr, long effect, long strength, Vibration vibration); static native void vibratorPerformComposedEffect(long controllerPtr, VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration); @@ -898,19 +895,11 @@ public class VibratorService extends IVibratorService.Stub } } - private final Runnable mVibrationEndRunnable = new Runnable() { - @Override - public void run() { - onVibrationFinished(); - } - }; - @GuardedBy("mLock") private void doCancelVibrateLocked() { Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked"); try { - mH.removeCallbacks(mVibrationEndRunnable); if (mThread != null) { mThread.cancel(); mThread = null; @@ -958,13 +947,11 @@ public class VibratorService extends IVibratorService.Stub private void startVibrationInnerLocked(Vibration vib) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked"); try { - long timeout = 0; mCurrentVibration = vib; if (vib.effect instanceof VibrationEffect.OneShot) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect; doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib); - timeout = oneShot.getDuration() * ASYNC_TIMEOUT_MULTIPLIER; } else if (vib.effect instanceof VibrationEffect.Waveform) { // mThread better be null here. doCancelVibrate should always be // called before startNextVibrationLocked or startVibrationLocked. @@ -973,24 +960,13 @@ public class VibratorService extends IVibratorService.Stub mThread.start(); } else if (vib.effect instanceof VibrationEffect.Prebaked) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); - timeout = doVibratorPrebakedEffectLocked(vib); + doVibratorPrebakedEffectLocked(vib); } else if (vib.effect instanceof VibrationEffect.Composed) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); doVibratorComposedEffectLocked(vib); - // FIXME: We rely on the completion callback here, but I don't think we require that - // devices which support composition also support the completion callback. If we - // ever get a device that supports the former but not the latter, then we have no - // real way of knowing how long a given effect should last. - timeout = 10_000; } else { Slog.e(TAG, "Unknown vibration type, ignoring"); } - // Post extra runnable to ensure vibration will end even if the HAL or native controller - // never triggers the callback. - // TODO: Move ASYNC_TIMEOUT_MULTIPLIER here once native controller is fully integrated. - if (timeout > 0) { - mH.postDelayed(mVibrationEndRunnable, timeout); - } } finally { Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); } @@ -1354,7 +1330,7 @@ public class VibratorService extends IVibratorService.Stub } @GuardedBy("mLock") - private long doVibratorPrebakedEffectLocked(Vibration vib) { + private void doVibratorPrebakedEffectLocked(Vibration vib) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked"); try { final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect; @@ -1364,25 +1340,20 @@ public class VibratorService extends IVibratorService.Stub } // Input devices don't support prebaked effect, so skip trying it with them. if (!usingInputDeviceVibrators) { - long duration = mNativeWrapper.vibratorPerformEffect(prebaked.getId(), - prebaked.getEffectStrength(), vib, - hasCapability(IVibrator.CAP_PERFORM_CALLBACK)); - long timeout = duration; - if (hasCapability(IVibrator.CAP_PERFORM_CALLBACK)) { - timeout *= ASYNC_TIMEOUT_MULTIPLIER; - } - if (timeout > 0) { + long duration = mNativeWrapper.vibratorPerformEffect( + prebaked.getId(), prebaked.getEffectStrength(), vib); + if (duration > 0) { noteVibratorOnLocked(vib.uid, duration); - return timeout; + return; } } if (!prebaked.shouldFallback()) { - return 0; + return; } VibrationEffect effect = getFallbackEffect(prebaked.getId()); if (effect == null) { Slog.w(TAG, "Failed to play prebaked effect, no fallback"); - return 0; + return; } Vibration fallbackVib = new Vibration(vib.token, effect, vib.attrs, vib.uid, vib.opPkg, vib.reason + " (fallback)"); @@ -1390,7 +1361,7 @@ public class VibratorService extends IVibratorService.Stub linkVibration(fallbackVib); applyVibrationIntensityScalingLocked(fallbackVib, intensity); startVibrationInnerLocked(fallbackVib); - return 0; + return; } finally { Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); } @@ -1789,9 +1760,9 @@ public class VibratorService extends IVibratorService.Stub } /** Turns vibrator on to perform one of the supported effects. */ - public long vibratorPerformEffect(long effect, long strength, Vibration vibration, - boolean withCallback) { - return VibratorService.vibratorPerformEffect(effect, strength, vibration, withCallback); + public long vibratorPerformEffect(long effect, long strength, Vibration vibration) { + return VibratorService.vibratorPerformEffect( + mNativeControllerPtr, effect, strength, vibration); } /** Turns vibrator on to perform one of the supported composed effects. */ diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 3eb26de3a675..23e9d1b552d5 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -494,6 +494,13 @@ public final class ActiveServices { ServiceRecord r = res.record; + if (allowBackgroundActivityStarts) { + r.allowBgActivityStartsOnServiceStart(); + } + + setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, + allowBackgroundActivityStarts); + if (!mAm.mUserController.exists(r.userId)) { Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId); return null; @@ -516,6 +523,21 @@ public final class ActiveServices { forcedStandby = true; } + if (fgRequired) { + if (!r.mAllowStartForeground) { + if (!r.mLoggedInfoAllowStartForeground) { + Slog.wtf(TAG, "Background started FGS " + r.mInfoAllowStartForeground); + r.mLoggedInfoAllowStartForeground = true; + } + if (mAm.mConstants.mFlagFgsStartRestrictionEnabled) { + Slog.w(TAG, "startForegroundService() not allowed due to " + + " mAllowStartForeground false: service " + + r.shortInstanceName); + forcedStandby = true; + } + } + } + // If this is a direct-to-foreground start, make sure it is allowed as per the app op. boolean forceSilentAbort = false; if (fgRequired) { @@ -688,18 +710,7 @@ public final class ActiveServices { "Not potential delay (user " + r.userId + " not started): " + r); } } - - if (allowBackgroundActivityStarts) { - r.allowBgActivityStartsOnServiceStart(); - } ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); - - if (!r.mAllowWhileInUsePermissionInFgs) { - r.mAllowWhileInUsePermissionInFgs = - shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid, - callingUid, service, r, allowBackgroundActivityStarts); - } - return cmp; } @@ -1369,6 +1380,7 @@ public final class ActiveServices { + r.shortInstanceName); } } + boolean alreadyStartedOp = false; boolean stopProcStatsOp = false; if (r.fgRequired) { @@ -1415,6 +1427,24 @@ public final class ActiveServices { ignoreForeground = true; } + if (!ignoreForeground) { + if (!r.mAllowStartForeground) { + if (!r.mLoggedInfoAllowStartForeground) { + Slog.wtf(TAG, "Background started FGS " + + r.mInfoAllowStartForeground); + r.mLoggedInfoAllowStartForeground = true; + } + if (mAm.mConstants.mFlagFgsStartRestrictionEnabled) { + Slog.w(TAG, + "Service.startForeground() not allowed due to " + + "mAllowStartForeground false: service " + + r.shortInstanceName); + updateServiceForegroundLocked(r.app, true); + ignoreForeground = true; + } + } + } + // Apps under strict background restrictions simply don't get to have foreground // services, so now that we've enforced the startForegroundService() contract // we only do the machinery of making the service foreground when the app @@ -2067,12 +2097,7 @@ public final class ActiveServices { } } - if (!s.mAllowWhileInUsePermissionInFgs) { - s.mAllowWhileInUsePermissionInFgs = - shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, - callingPid, callingUid, - service, s, false); - } + setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, false); if (s.app != null) { if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { @@ -4840,21 +4865,48 @@ public final class ActiveServices { } /** - * Should allow while-in-use permissions in foreground service or not. - * while-in-use permissions in FGS started from background might be restricted. + * There are two FGS restrictions: + * In R, mAllowWhileInUsePermissionInFgs is to allow while-in-use permissions in foreground + * service or not. while-in-use permissions in FGS started from background might be restricted. + * In S, mAllowStartForeground is to allow FGS to startForeground or not. Service started + * from background may not become a FGS. * @param callingPackage caller app's package name. * @param callingUid caller app's uid. * @param intent intent to start/bind service. * @param r the service to start. * @return true if allow, false otherwise. */ - private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage, + private void setFgsRestrictionLocked(String callingPackage, int callingPid, int callingUid, Intent intent, ServiceRecord r, boolean allowBackgroundActivityStarts) { - // Is the background FGS start restriction turned on? + // Check DeviceConfig flag. if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) { - return true; + r.mAllowWhileInUsePermissionInFgs = true; + } + + if (!r.mAllowWhileInUsePermissionInFgs || !r.mAllowStartForeground) { + final boolean temp = shouldAllowFgsFeatureLocked(callingPackage, callingPid, + callingUid, intent, r, allowBackgroundActivityStarts); + if (!r.mAllowWhileInUsePermissionInFgs) { + r.mAllowWhileInUsePermissionInFgs = temp; + } + if (!r.mAllowStartForeground) { + r.mAllowStartForeground = temp; + } } + } + + /** + * Should allow FGS feature or not. + * @param callingPackage caller app's package name. + * @param callingUid caller app's uid. + * @param intent intent to start/bind service. + * @param r the service to start. + * @return true if allow, false otherwise. + */ + private boolean shouldAllowFgsFeatureLocked(String callingPackage, + int callingPid, int callingUid, Intent intent, ServiceRecord r, + boolean allowBackgroundActivityStarts) { // Is the allow activity background start flag on? if (allowBackgroundActivityStarts) { return true; @@ -4894,10 +4946,11 @@ public final class ActiveServices { } // Is the calling UID at PROCESS_STATE_TOP or above? - final boolean isCallingUidTopApp = appIsTopLocked(callingUid); - if (isCallingUidTopApp) { + final int uidState = mAm.getUidState(callingUid); + if (uidState <= ActivityManager.PROCESS_STATE_TOP) { return true; } + // Does the calling UID have any visible activity? final boolean isCallingUidVisible = mAm.mAtmInternal.isUidForeground(callingUid); if (isCallingUidVisible) { @@ -4915,6 +4968,19 @@ public final class ActiveServices { if (isDeviceOwner) { return true; } + + final String info = + "[callingPackage: " + callingPackage + + "; callingUid: " + callingUid + + "; uidState: " + ProcessList.makeProcStateString(uidState) + + "; intent: " + intent + + "; targetSdkVersion:" + r.appInfo.targetSdkVersion + + "]"; + if (!info.equals(r.mInfoAllowStartForeground)) { + r.mLoggedInfoAllowStartForeground = false; + r.mInfoAllowStartForeground = info; + } + return false; } } diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 775119c18037..e9539be8b0d5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -144,6 +144,13 @@ final class ActivityManagerConstants extends ContentObserver { private static final String KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED = "default_background_fgs_starts_restriction_enabled"; + /** + * Default value for mFlagFgsStartRestrictionEnabled if not explicitly set in + * Settings.Global. + */ + private static final String KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED = + "default_fgs_starts_restriction_enabled"; + // Maximum number of cached processes we will allow. public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES; @@ -293,6 +300,11 @@ final class ActivityManagerConstants extends ContentObserver { // started, the restriction is on while-in-use permissions.) volatile boolean mFlagBackgroundFgsStartRestrictionEnabled = true; + // Indicates whether the foreground service background start restriction is enabled. + // When the restriction is enabled, service is not allowed to startForeground from background + // at all. + volatile boolean mFlagFgsStartRestrictionEnabled = false; + private final ActivityManagerService mService; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -436,6 +448,9 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED: updateBackgroundFgsStartsRestriction(); break; + case KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED: + updateFgsStartsRestriction(); + break; case KEY_OOMADJ_UPDATE_POLICY: updateOomAdjUpdatePolicy(); break; @@ -659,6 +674,7 @@ final class ActivityManagerConstants extends ContentObserver { mFlagForegroundServiceStartsLoggingEnabled = Settings.Global.getInt(mResolver, Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED, 1) == 1; } + private void updateBackgroundFgsStartsRestriction() { mFlagBackgroundFgsStartRestrictionEnabled = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, @@ -666,6 +682,13 @@ final class ActivityManagerConstants extends ContentObserver { /*defaultValue*/ true); } + private void updateFgsStartsRestriction() { + mFlagFgsStartRestrictionEnabled = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED, + /*defaultValue*/ false); + } + private void updateOomAdjUpdatePolicy() { OOMADJ_UPDATE_QUICK = DeviceConfig.getInt( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b62ff1c26f8f..22c3b938e1ce 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1581,6 +1581,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; static final int KILL_APP_ZYGOTE_MSG = 71; static final int BINDER_HEAVYHITTER_AUTOSAMPLER_TIMEOUT_MSG = 72; + static final int WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG = 73; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1917,6 +1918,11 @@ public class ActivityManagerService extends IActivityManager.Stub case BINDER_HEAVYHITTER_AUTOSAMPLER_TIMEOUT_MSG: { handleBinderHeavyHitterAutoSamplerTimeOut(); } break; + case WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG: { + synchronized (ActivityManagerService.this) { + ((ContentProviderRecord) msg.obj).onProviderPublishStatusLocked(false); + } + } break; } } } @@ -4603,10 +4609,12 @@ public class ActivityManagerService extends IActivityManager.Stub proc.lastMemInfoTime = SystemClock.uptimeMillis(); if (proc.thread != null && proc.setAdj == oomAdj) { // Record this for posterity if the process has been stable. - proc.baseProcessTracker.addPss(infos[i].getTotalPss(), - infos[i].getTotalUss(), infos[i].getTotalRss(), false, - ProcessStats.ADD_PSS_EXTERNAL_SLOW, endTime - startTime, - proc.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + proc.baseProcessTracker.addPss(infos[i].getTotalPss(), + infos[i].getTotalUss(), infos[i].getTotalRss(), false, + ProcessStats.ADD_PSS_EXTERNAL_SLOW, endTime - startTime, + proc.pkgList.mPkgList); + } for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) { ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg); FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED, @@ -4663,8 +4671,11 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { if (proc.thread != null && proc.setAdj == oomAdj) { // Record this for posterity if the process has been stable. - proc.baseProcessTracker.addPss(pss[i], tmpUss[0], tmpUss[2], false, - ProcessStats.ADD_PSS_EXTERNAL, endTime-startTime, proc.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + proc.baseProcessTracker.addPss(pss[i], tmpUss[0], tmpUss[2], false, + ProcessStats.ADD_PSS_EXTERNAL, endTime - startTime, + proc.pkgList.mPkgList); + } for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) { ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg); FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED, @@ -12101,8 +12112,10 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { if (r.thread != null && oomAdj == r.getSetAdjWithServices()) { // Record this for posterity if the process has been stable. - r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true, - reportType, endTime-startTime, r.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true, + reportType, endTime - startTime, r.pkgList.mPkgList); + } for (int ipkg = r.pkgList.size() - 1; ipkg >= 0; ipkg--) { ProcessStats.ProcessStateHolder holder = r.pkgList.valueAt(ipkg); FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED, @@ -12707,8 +12720,10 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { if (r.thread != null && oomAdj == r.getSetAdjWithServices()) { // Record this for posterity if the process has been stable. - r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true, - reportType, endTime-startTime, r.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true, + reportType, endTime - startTime, r.pkgList.mPkgList); + } for (int ipkg = r.pkgList.size() - 1; ipkg >= 0; ipkg--) { ProcessStats.ProcessStateHolder holder = r.pkgList.valueAt(ipkg); FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED, @@ -14470,7 +14485,7 @@ public class ActivityManagerService extends IActivityManager.Stub resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId, false /* allowBackgroundActivityStarts */, - null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastWhitelist */); + null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */); } @GuardedBy("this") @@ -15314,7 +15329,7 @@ public class ActivityManagerService extends IActivityManager.Stub OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid, realCallingPid, userId, allowBackgroundActivityStarts, backgroundActivityStartsToken, - null /*broadcastWhitelist*/); + null /* broadcastAllowList */); } finally { Binder.restoreCallingIdentity(origId); } @@ -15921,8 +15936,10 @@ public class ActivityManagerService extends IActivityManager.Stub EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024, swapPss * 1024, rss * 1024, statType, procState, pssDuration); proc.lastPssTime = now; - proc.baseProcessTracker.addPss( - pss, uss, rss, true, statType, pssDuration, proc.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + proc.baseProcessTracker.addPss( + pss, uss, rss, true, statType, pssDuration, proc.pkgList.mPkgList); + } for (int ipkg = proc.pkgList.mPkgList.size() - 1; ipkg >= 0; ipkg--) { ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg); FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED, @@ -16283,7 +16300,9 @@ public class ActivityManagerService extends IActivityManager.Stub ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE, ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU, true); - app.baseProcessTracker.reportExcessiveCpu(app.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + app.baseProcessTracker.reportExcessiveCpu(app.pkgList.mPkgList); + } for (int ipkg = app.pkgList.size() - 1; ipkg >= 0; ipkg--) { ProcessStats.ProcessStateHolder holder = app.pkgList.valueAt(ipkg); FrameworkStatsLog.write(FrameworkStatsLog.EXCESSIVE_CPU_USAGE_REPORTED, @@ -16395,11 +16414,13 @@ public class ActivityManagerService extends IActivityManager.Stub } final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) { - if (proc.thread != null && proc.baseProcessTracker != null) { - final int procState = proc.getReportedProcState(); - if (procState != PROCESS_STATE_NONEXISTENT) { - proc.baseProcessTracker.setState( - procState, memFactor, now, proc.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + if (proc.thread != null && proc.baseProcessTracker != null) { + final int procState = proc.getReportedProcState(); + if (procState != PROCESS_STATE_NONEXISTENT) { + proc.baseProcessTracker.setState( + procState, memFactor, now, proc.pkgList.mPkgList); + } } } } diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java index 5cc7aba736e1..bfba4afcd4e4 100644 --- a/services/core/java/com/android/server/am/ContentProviderHelper.java +++ b/services/core/java/com/android/server/am/ContentProviderHelper.java @@ -50,6 +50,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.IBinder; +import android.os.Message; import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteException; @@ -218,7 +219,7 @@ public class ContentProviderHelper { // of being published... but it is also allowed to run // in the caller's process, so don't make a connection // and just let the caller instantiate its own instance. - ContentProviderHolder holder = cpr.newHolder(null); + ContentProviderHolder holder = cpr.newHolder(null, true); // don't give caller the provider object, it needs to make its own. holder.provider = null; return holder; @@ -415,7 +416,7 @@ public class ContentProviderHelper { // info and allow the caller to instantiate it. Only do // this if the provider is the same user as the caller's // process, or can run as root (so can be in any process). - return cpr.newHolder(null); + return cpr.newHolder(null, true); } if (ActivityManagerDebugConfig.DEBUG_PROVIDER) { @@ -513,6 +514,38 @@ public class ContentProviderHelper { UserHandle.getAppId(cpi.applicationInfo.uid)); } + if (caller != null) { + // The client will be waiting, and we'll notify it when the provider is ready. + synchronized (cpr) { + if (cpr.provider == null) { + if (cpr.launchingApp == null) { + Slog.w(TAG, "Unable to launch app " + + cpi.applicationInfo.packageName + "/" + + cpi.applicationInfo.uid + " for provider " + + name + ": launching app became null"); + EventLogTags.writeAmProviderLostProcess( + UserHandle.getUserId(cpi.applicationInfo.uid), + cpi.applicationInfo.packageName, + cpi.applicationInfo.uid, name); + return null; + } + + if (conn != null) { + conn.waiting = true; + } + Message msg = mService.mHandler.obtainMessage( + ActivityManagerService.WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG); + msg.obj = cpr; + mService.mHandler.sendMessageDelayed(msg, + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS); + } + } + // Return a holder instance even if we are waiting for the publishing of the provider, + // client will check for the holder.provider to see if it needs to wait for it. + return cpr.newHolder(conn, false); + } + + // Because of the provider's external client (i.e., SHELL), we'll have to wait right here. // Wait for the provider to be published... final long timeout = SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS; @@ -569,7 +602,7 @@ public class ContentProviderHelper { + " caller=" + callerName + "/" + Binder.getCallingUid()); return null; } - return cpr.newHolder(conn); + return cpr.newHolder(conn, false); } void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) { @@ -622,6 +655,8 @@ public class ContentProviderHelper { } if (wasInLaunchingProviders) { mService.mHandler.removeMessages( + ActivityManagerService.WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG, dst); + mService.mHandler.removeMessages( ActivityManagerService.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r); } // Make sure the package is associated with the process. @@ -635,6 +670,7 @@ public class ContentProviderHelper { dst.provider = src.provider; dst.setProcess(r); dst.notifyAll(); + dst.onProviderPublishStatusLocked(true); } dst.mRestartCount = 0; mService.updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER); @@ -1504,6 +1540,9 @@ public class ContentProviderHelper { synchronized (cpr) { cpr.launchingApp = null; cpr.notifyAll(); + cpr.onProviderPublishStatusLocked(false); + mService.mHandler.removeMessages( + ActivityManagerService.WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG, cpr); } final int userId = UserHandle.getUserId(cpr.uid); // Don't remove from provider map if it doesn't match diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java index d8d8cccc05f3..fb8b5d480b27 100644 --- a/services/core/java/com/android/server/am/ContentProviderRecord.java +++ b/services/core/java/com/android/server/am/ContentProviderRecord.java @@ -85,11 +85,12 @@ final class ContentProviderRecord implements ComponentName.WithComponentName { noReleaseNeeded = cpr.noReleaseNeeded; } - public ContentProviderHolder newHolder(ContentProviderConnection conn) { + public ContentProviderHolder newHolder(ContentProviderConnection conn, boolean local) { ContentProviderHolder holder = new ContentProviderHolder(info); holder.provider = provider; holder.noReleaseNeeded = noReleaseNeeded; holder.connection = conn; + holder.mLocal = local; return holder; } @@ -179,6 +180,50 @@ final class ContentProviderRecord implements ComponentName.WithComponentName { return !connections.isEmpty() || hasExternalProcessHandles(); } + /** + * Notify all clients that the provider has been published and ready to use, + * or timed out. + * + * @param status true: successfully published; false: timed out + */ + void onProviderPublishStatusLocked(boolean status) { + final int numOfConns = connections.size(); + final int userId = UserHandle.getUserId(appInfo.uid); + for (int i = 0; i < numOfConns; i++) { + final ContentProviderConnection conn = connections.get(i); + if (conn.waiting && conn.client != null) { + final ProcessRecord client = conn.client; + if (!status) { + if (launchingApp == null) { + Slog.w(TAG_AM, "Unable to launch app " + + appInfo.packageName + "/" + + appInfo.uid + " for provider " + + info.authority + ": launching app became null"); + EventLogTags.writeAmProviderLostProcess( + userId, + appInfo.packageName, + appInfo.uid, info.authority); + } else { + Slog.wtf(TAG_AM, "Timeout waiting for provider " + + appInfo.packageName + "/" + + appInfo.uid + " for provider " + + info.authority + + " caller=" + client); + } + } + if (client.thread != null) { + try { + client.thread.notifyContentProviderPublishStatus( + newHolder(status ? conn : null, false), + info.authority, userId, status); + } catch (RemoteException e) { + } + } + } + conn.waiting = false; + } + } + void dump(PrintWriter pw, String prefix, boolean full) { if (full) { pw.print(prefix); pw.print("package="); diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index e3e13391a8b0..14bc6cbed7d7 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -1079,8 +1079,8 @@ class ProcessRecord implements WindowProcessListener { */ public void resetPackageList(ProcessStatsService tracker) { final int N = pkgList.size(); - if (baseProcessTracker != null) { - synchronized (tracker.mLock) { + synchronized (tracker.mLock) { + if (baseProcessTracker != null) { long now = SystemClock.uptimeMillis(); baseProcessTracker.setState(ProcessStats.STATE_NOTHING, tracker.getMemFactorLocked(), now, pkgList.mPkgList); @@ -1108,10 +1108,11 @@ class ProcessRecord implements WindowProcessListener { holder.state.makeActive(); } } + } else if (N != 1) { + pkgList.clear(); + pkgList.put(info.packageName, + new ProcessStats.ProcessStateHolder(info.longVersionCode)); } - } else if (N != 1) { - pkgList.clear(); - pkgList.put(info.packageName, new ProcessStats.ProcessStateHolder(info.longVersionCode)); } } diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 4a2703056871..66677b67b6aa 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -146,6 +146,12 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN // the most recent package that start/bind this service. String mRecentCallingPackage; + // allow the service becomes foreground service? Service started from background may not be + // allowed to become a foreground service. + boolean mAllowStartForeground; + String mInfoAllowStartForeground; + boolean mLoggedInfoAllowStartForeground; + String stringName; // caching of toString private int lastStartId; // identifier of most recent start request. @@ -408,6 +414,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN pw.println(mAllowWhileInUsePermissionInFgs); pw.print(prefix); pw.print("recentCallingPackage="); pw.println(mRecentCallingPackage); + pw.print(prefix); pw.print("allowStartForeground="); + pw.println(mAllowStartForeground); + pw.print(prefix); pw.print("infoAllowStartForeground="); + pw.println(mInfoAllowStartForeground); if (delayed) { pw.print(prefix); pw.print("delayed="); pw.println(delayed); } diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 0658e8139cc2..7420e0a6e828 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -1630,7 +1630,7 @@ class UserController implements Handler.Callback { UserInfo currentUserInfo = getUserInfo(currentUserId); Pair<UserInfo, UserInfo> userNames = new Pair<>(currentUserInfo, targetUserInfo); mUiHandler.removeMessages(START_USER_SWITCH_UI_MSG); - mUiHandler.sendMessage(mHandler.obtainMessage( + mUiHandler.sendMessage(mUiHandler.obtainMessage( START_USER_SWITCH_UI_MSG, userNames)); } else { mHandler.removeMessages(START_USER_SWITCH_FG_MSG); @@ -2887,13 +2887,18 @@ class UserController implements Handler.Callback { void showUserSwitchingDialog(UserInfo fromUser, UserInfo toUser, String switchingFromSystemUserMessage, String switchingToSystemUserMessage) { - if (!mService.mContext.getPackageManager() + if (mService.mContext.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { - final Dialog d = new UserSwitchingDialog(mService, mService.mContext, fromUser, - toUser, true /* above system */, switchingFromSystemUserMessage, - switchingToSystemUserMessage); - d.show(); - } + // config_customUserSwitchUi is set to true on Automotive as CarSystemUI is + // responsible to show the UI; OEMs should not change that, but if they do, we + // should at least warn the user... + Slog.w(TAG, "Showing user switch dialog on UserController, it could cause a race " + + "condition if it's shown by CarSystemUI as well"); + } + final Dialog d = new UserSwitchingDialog(mService, mService.mContext, fromUser, + toUser, true /* above system */, switchingFromSystemUserMessage, + switchingToSystemUserMessage); + d.show(); } void reportGlobalUsageEventLocked(int event) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 0a179e89f757..bf7c68a845c5 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1283,7 +1283,6 @@ public class AudioService extends IAudioService.Stub } if (isPlatformTelevision()) { - checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, caller); synchronized (mHdmiClientLock) { if (mHdmiManager != null && mHdmiPlaybackClient != null) { updateHdmiCecSinkLocked(mHdmiCecSink | false); @@ -1303,22 +1302,54 @@ public class AudioService extends IAudioService.Stub } } - private void checkAddAllFixedVolumeDevices(int device, String caller) { + /** + * Update volume states for the given device. + * + * This will initialize the volume index if no volume index is available. + * If the device is the currently routed device, fixed/full volume policies will be applied. + * + * @param device a single audio device, ensure that this is not a devices bitmask + * @param caller caller of this method + */ + private void updateVolumeStatesForAudioDevice(int device, String caller) { final int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = 0; streamType < numStreamTypes; streamType++) { - if (!mStreamStates[streamType].hasIndexForDevice(device)) { - // set the default value, if device is affected by a full/fix/abs volume rule, it - // will taken into account in checkFixedVolumeDevices() - mStreamStates[streamType].setIndex( - mStreamStates[mStreamVolumeAlias[streamType]] - .getIndex(AudioSystem.DEVICE_OUT_DEFAULT), - device, caller, true /*hasModifyAudioSettings*/); - } - mStreamStates[streamType].checkFixedVolumeDevices(); + updateVolumeStates(device, streamType, caller); + } + } - // Unmute streams if device is full volume - if (mFullVolumeDevices.contains(device)) { - mStreamStates[streamType].mute(false); + /** + * Update volume states for the given device and given stream. + * + * This will initialize the volume index if no volume index is available. + * If the device is the currently routed device, fixed/full volume policies will be applied. + * + * @param device a single audio device, ensure that this is not a devices bitmask + * @param streamType streamType to be updated + * @param caller caller of this method + */ + private void updateVolumeStates(int device, int streamType, String caller) { + if (!mStreamStates[streamType].hasIndexForDevice(device)) { + // set the default value, if device is affected by a full/fix/abs volume rule, it + // will taken into account in checkFixedVolumeDevices() + mStreamStates[streamType].setIndex( + mStreamStates[mStreamVolumeAlias[streamType]] + .getIndex(AudioSystem.DEVICE_OUT_DEFAULT), + device, caller, true /*hasModifyAudioSettings*/); + } + + // Check if device to be updated is routed for the given audio stream + List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributesInt( + new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build()); + for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) { + if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType( + device)) { + mStreamStates[streamType].checkFixedVolumeDevices(); + + // Unmute streams if required if device is full volume + if (isStreamMute(streamType) && mFullVolumeDevices.contains(device)) { + mStreamStates[streamType].mute(false); + } } } } @@ -1868,8 +1899,13 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#getDevicesForAttributes(AudioAttributes) */ public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes( @NonNull AudioAttributes attributes) { - Objects.requireNonNull(attributes); enforceModifyAudioRoutingPermission(); + return getDevicesForAttributesInt(attributes); + } + + protected @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesInt( + @NonNull AudioAttributes attributes) { + Objects.requireNonNull(attributes); return AudioSystem.getDevicesForAttributes(attributes); } @@ -4916,7 +4952,15 @@ public class AudioService extends IAudioService.Stub synchronized (VolumeStreamState.class) { for (int stream = 0; stream < mStreamStates.length; stream++) { if (stream != skipStream) { - mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/); + int devices = mStreamStates[stream].observeDevicesForStream_syncVSS( + false /*checkOthers*/); + + Set<Integer> devicesSet = AudioSystem.generateAudioDeviceTypesSet(devices); + for (Integer device : devicesSet) { + // Update volume states for devices routed for the stream + updateVolumeStates(device, stream, + "AudioService#observeDevicesForStreams"); + } } } } @@ -4985,7 +5029,7 @@ public class AudioService extends IAudioService.Stub + Integer.toHexString(audioSystemDeviceOut) + " from:" + caller)); // make sure we have a volume entry for this device, and that volume is updated according // to volume behavior - checkAddAllFixedVolumeDevices(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller); + updateVolumeStatesForAudioDevice(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller); } /** @@ -7207,10 +7251,9 @@ public class AudioService extends IAudioService.Stub // HDMI output removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI); } + updateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI, + "HdmiPlaybackClient.DisplayStatusCallback"); } - - checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, - "HdmiPlaybackClient.DisplayStatusCallback"); } private class MyHdmiControlStatusChangeListenerCallback diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index 7202f0f401f9..7f9b3c9fcff7 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -56,7 +56,6 @@ import android.system.OsConstants; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; -import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -130,7 +129,42 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse } } - public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) { + /** + * A data class to store each uid Netd permission information. Netd permissions includes + * PERMISSION_NETWORK, PERMISSION_SYSTEM, PERMISSION_INTERNET, PERMISSION_UPDATE_DEVICE_STATS + * and OR'd with the others. Default permission is PERMISSION_NONE and PERMISSION_UNINSTALLED + * will be set if all packages are removed from the uid. + */ + public static class UidNetdPermissionInfo { + private final int mNetdPermissions; + + UidNetdPermissionInfo() { + this(PERMISSION_NONE); + } + + UidNetdPermissionInfo(int permissions) { + mNetdPermissions = permissions; + } + + /** Plus given permissions and return new UidNetdPermissionInfo instance. */ + public UidNetdPermissionInfo plusNetdPermissions(int permissions) { + return new UidNetdPermissionInfo(mNetdPermissions | permissions); + } + + /** Return whether package is uninstalled. */ + public boolean isPackageUninstalled() { + return mNetdPermissions == PERMISSION_UNINSTALLED; + } + + /** Check that uid has given permissions */ + public boolean hasNetdPermissions(final int permissions) { + if (isPackageUninstalled()) return false; + if (permissions == PERMISSION_NONE) return true; + return (mNetdPermissions & permissions) == permissions; + } + } + + public PermissionMonitor(Context context, INetd netd) { this(context, netd, new Dependencies()); } @@ -161,7 +195,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse return; } - SparseIntArray netdPermsUids = new SparseIntArray(); + final SparseArray<UidNetdPermissionInfo> netdPermsUids = new SparseArray<>(); for (PackageInfo app : apps) { int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID; @@ -183,9 +217,13 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse } } + // Skip already checked uid. + if (netdPermsUids.get(uid) != null) continue; + //TODO: unify the management of the permissions into one codepath. - final int otherNetdPerms = getNetdPermissionMask(uid); - netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms); + final UidNetdPermissionInfo permInfo = + new UidNetdPermissionInfo(getNetdPermissionMask(uid)); + netdPermsUids.put(uid, permInfo); } List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users @@ -207,7 +245,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse ? PERMISSION_UPDATE_DEVICE_STATS : 0; netdPermission |= perms.contains(INTERNET) ? PERMISSION_INTERNET : 0; } - netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission); + final UidNetdPermissionInfo permInfo = netdPermsUids.get(uid); + netdPermsUids.put(uid, permInfo != null + ? permInfo.plusNetdPermissions(netdPermission) + : new UidNetdPermissionInfo(netdPermission)); } log("Users: " + mUsers.size() + ", Apps: " + mApps.size()); update(mUsers, mApps, true); @@ -341,15 +382,15 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse return currentPermission; } - private int getPermissionForUid(final int uid) { + private UidNetdPermissionInfo getPermissionForUid(final int uid) { // Check all the packages for this UID. The UID has the permission if any of the // packages in it has the permission. final String[] packages = mPackageManager.getPackagesForUid(uid); if (packages == null || packages.length <= 0) { // The last package of this uid is removed from device. Clean the package up. - return PERMISSION_UNINSTALLED; + return new UidNetdPermissionInfo(PERMISSION_UNINSTALLED); } - return getNetdPermissionMask(uid); + return new UidNetdPermissionInfo(getNetdPermissionMask(uid)); } /** @@ -599,28 +640,28 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse * permission information to netd. * * @param uid the app uid of the package installed - * @param permissions the permissions the app requested and netd cares about. + * @param permissionInfo the permission info of given uid. * * @hide */ @VisibleForTesting - void sendPackagePermissionsForUid(int uid, int permissions) { - SparseIntArray netdPermissionsAppIds = new SparseIntArray(); - netdPermissionsAppIds.put(uid, permissions); - sendPackagePermissionsToNetd(netdPermissionsAppIds); + void sendPackagePermissionsForUid(int uid, UidNetdPermissionInfo permissionInfo) { + final SparseArray<UidNetdPermissionInfo> uidsPermInfo = new SparseArray<>(); + uidsPermInfo.put(uid, permissionInfo); + sendPackagePermissionsToNetd(uidsPermInfo); } /** * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET * and/or UPDATE_DEVICE_STATS permission of the uids in array. * - * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the - * permission is 0, revoke all permissions of that uid. - * + * @param uidsPermInfo permission info array generated from each uid. If the uid permission is + * PERMISSION_NONE or PERMISSION_UNINSTALLED, revoke all permissions of that + * uid. * @hide */ @VisibleForTesting - void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) { + void sendPackagePermissionsToNetd(final SparseArray<UidNetdPermissionInfo> uidsPermInfo) { if (mNetd == null) { Log.e(TAG, "Failed to get the netd service"); return; @@ -630,26 +671,20 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>(); ArrayList<Integer> noPermissionAppIds = new ArrayList<>(); ArrayList<Integer> uninstalledAppIds = new ArrayList<>(); - for (int i = 0; i < netdPermissionsAppIds.size(); i++) { - int permissions = netdPermissionsAppIds.valueAt(i); - switch(permissions) { - case (PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS): - allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); - break; - case PERMISSION_INTERNET: - internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); - break; - case PERMISSION_UPDATE_DEVICE_STATS: - updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); - break; - case PERMISSION_NONE: - noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); - break; - case PERMISSION_UNINSTALLED: - uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i)); - default: - Log.e(TAG, "unknown permission type: " + permissions + "for uid: " - + netdPermissionsAppIds.keyAt(i)); + for (int i = 0; i < uidsPermInfo.size(); i++) { + final int uid = uidsPermInfo.keyAt(i); + final UidNetdPermissionInfo permInfo = uidsPermInfo.valueAt(i); + if (permInfo.hasNetdPermissions( + PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS)) { + allPermissionAppIds.add(uid); + } else if (permInfo.hasNetdPermissions(PERMISSION_INTERNET)) { + internetPermissionAppIds.add(uid); + } else if (permInfo.hasNetdPermissions(PERMISSION_UPDATE_DEVICE_STATS)) { + updateStatsPermissionAppIds.add(uid); + } else if (permInfo.isPackageUninstalled()) { + uninstalledAppIds.add(uid); + } else { + noPermissionAppIds.add(uid); } } try { diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 1c93d4eb599b..5484bfca5851 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -153,8 +153,8 @@ public class Vpn { private static final boolean LOGD = true; // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on - // the device idle whitelist during service launch and VPN bootstrap. - private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS = 60 * 1000; + // the device idle allowlist during service launch and VPN bootstrap. + private static final long VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS = 60 * 1000; // Settings for how much of the address space should be routed so that Vpn considers // "most" of the address space is routed. This is used to determine whether this Vpn @@ -180,7 +180,8 @@ public class Vpn { // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm // is actually O(n²)+O(n²). private static final int MAX_ROUTES_TO_EVALUATE = 150; - + private static final String LOCKDOWN_ALLOWLIST_SETTING_NAME = + Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST; /** * Largest profile size allowable for Platform VPNs. * @@ -236,7 +237,7 @@ public class Vpn { * Set of packages in addition to the VPN app itself that can access the network directly when * VPN is not connected even if {@code mLockdown} is set. */ - private @NonNull List<String> mLockdownWhitelist = Collections.emptyList(); + private @NonNull List<String> mLockdownAllowlist = Collections.emptyList(); /** * A memory of what UIDs this class told netd to block for the lockdown feature. @@ -520,7 +521,7 @@ public class Vpn { } } if (!hadUnderlyingNetworks) { - // No idea what the underlying networks are; assume sane defaults + // No idea what the underlying networks are; assume the safer defaults metered = true; roaming = false; congested = false; @@ -653,18 +654,18 @@ public class Vpn { * * @param packageName the package to designate as always-on VPN supplier. * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. - * @param lockdownWhitelist packages to be whitelisted from lockdown. + * @param lockdownAllowlist packages to be allowed from lockdown. * @param keyStore the Keystore instance to use for checking of PlatformVpnProfile(s) * @return {@code true} if the package has been set as always-on, {@code false} otherwise. */ public synchronized boolean setAlwaysOnPackage( @Nullable String packageName, boolean lockdown, - @Nullable List<String> lockdownWhitelist, + @Nullable List<String> lockdownAllowlist, @NonNull KeyStore keyStore) { enforceControlPermissionOrInternalCaller(); - if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownWhitelist, keyStore)) { + if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist, keyStore)) { saveAlwaysOnPackage(); return true; } @@ -679,7 +680,7 @@ public class Vpn { * * @param packageName the package to designate as always-on VPN supplier. * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. - * @param lockdownWhitelist packages to be whitelisted from lockdown. This is only used if + * @param lockdownAllowlist packages to be allowed to bypass lockdown. This is only used if * {@code lockdown} is {@code true}. Packages must not contain commas. * @param keyStore the system keystore instance to check for profiles * @return {@code true} if the package has been set as always-on, {@code false} otherwise. @@ -687,16 +688,16 @@ public class Vpn { @GuardedBy("this") private boolean setAlwaysOnPackageInternal( @Nullable String packageName, boolean lockdown, - @Nullable List<String> lockdownWhitelist, @NonNull KeyStore keyStore) { + @Nullable List<String> lockdownAllowlist, @NonNull KeyStore keyStore) { if (VpnConfig.LEGACY_VPN.equals(packageName)) { Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on."); return false; } - if (lockdownWhitelist != null) { - for (String pkg : lockdownWhitelist) { + if (lockdownAllowlist != null) { + for (String pkg : lockdownAllowlist) { if (pkg.contains(",")) { - Log.w(TAG, "Not setting always-on vpn, invalid whitelisted package: " + pkg); + Log.w(TAG, "Not setting always-on vpn, invalid allowed package: " + pkg); return false; } } @@ -724,8 +725,8 @@ public class Vpn { } mLockdown = (mAlwaysOn && lockdown); - mLockdownWhitelist = (mLockdown && lockdownWhitelist != null) - ? Collections.unmodifiableList(new ArrayList<>(lockdownWhitelist)) + mLockdownAllowlist = (mLockdown && lockdownAllowlist != null) + ? Collections.unmodifiableList(new ArrayList<>(lockdownAllowlist)) : Collections.emptyList(); if (isCurrentPreparedPackage(packageName)) { @@ -754,10 +755,10 @@ public class Vpn { } /** - * @return an immutable list of packages whitelisted from always-on VPN lockdown. + * @return an immutable list of packages allowed to bypass always-on VPN lockdown. */ - public synchronized List<String> getLockdownWhitelist() { - return mLockdown ? mLockdownWhitelist : null; + public synchronized List<String> getLockdownAllowlist() { + return mLockdown ? mLockdownAllowlist : null; } /** @@ -772,8 +773,8 @@ public class Vpn { mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, (mAlwaysOn && mLockdown ? 1 : 0), mUserHandle); mSystemServices.settingsSecurePutStringForUser( - Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, - String.join(",", mLockdownWhitelist), mUserHandle); + LOCKDOWN_ALLOWLIST_SETTING_NAME, + String.join(",", mLockdownAllowlist), mUserHandle); } finally { Binder.restoreCallingIdentity(token); } @@ -788,12 +789,12 @@ public class Vpn { Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle); final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser( Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0; - final String whitelistString = mSystemServices.settingsSecureGetStringForUser( - Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, mUserHandle); - final List<String> whitelistedPackages = TextUtils.isEmpty(whitelistString) - ? Collections.emptyList() : Arrays.asList(whitelistString.split(",")); + final String allowlistString = mSystemServices.settingsSecureGetStringForUser( + LOCKDOWN_ALLOWLIST_SETTING_NAME, mUserHandle); + final List<String> allowedPackages = TextUtils.isEmpty(allowlistString) + ? Collections.emptyList() : Arrays.asList(allowlistString.split(",")); setAlwaysOnPackageInternal( - alwaysOnPackage, alwaysOnLockdown, whitelistedPackages, keyStore); + alwaysOnPackage, alwaysOnLockdown, allowedPackages, keyStore); } finally { Binder.restoreCallingIdentity(token); } @@ -849,7 +850,7 @@ public class Vpn { DeviceIdleInternal idleController = LocalServices.getService(DeviceIdleInternal.class); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage, - VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS, mUserHandle, false, "vpn"); + VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserHandle, false, "vpn"); // Start the VPN service declared in the app's manifest. Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE); @@ -1212,7 +1213,7 @@ public class Vpn { // applications have changed. Consider diffing UID ranges and only applying the delta. if (!Objects.equals(oldConfig.allowedApplications, mConfig.allowedApplications) || !Objects.equals(oldConfig.disallowedApplications, mConfig.disallowedApplications)) { - Log.i(TAG, "Handover not possible due to changes to whitelisted/blacklisted apps"); + Log.i(TAG, "Handover not possible due to changes to allowed/denied apps"); return false; } @@ -1440,13 +1441,13 @@ public class Vpn { * associated with one user, and any restricted profiles attached to that user. * * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, - * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs + * the UID ranges will match the app list specified there. Otherwise, all UIDs * in each user and profile will be included. * * @param userHandle The userId to create UID ranges for along with any of its restricted * profiles. - * @param allowedApplications (optional) whitelist of applications to include. - * @param disallowedApplications (optional) blacklist of applications to exclude. + * @param allowedApplications (optional) List of applications to allow. + * @param disallowedApplications (optional) List of applications to deny. */ @VisibleForTesting Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userHandle, @@ -1480,13 +1481,13 @@ public class Vpn { * associated with one user. * * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, - * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs + * the UID ranges will match the app allowlist or denylist specified there. Otherwise, all UIDs * in the user will be included. * * @param ranges {@link Set} of {@link UidRange}s to which to add. * @param userHandle The userId to add to {@param ranges}. - * @param allowedApplications (optional) whitelist of applications to include. - * @param disallowedApplications (optional) blacklist of applications to exclude. + * @param allowedApplications (optional) allowlist of applications to include. + * @param disallowedApplications (optional) denylist of applications to exclude. */ @VisibleForTesting void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userHandle, @@ -1608,7 +1609,7 @@ public class Vpn { /** * Restricts network access from all UIDs affected by this {@link Vpn}, apart from the VPN - * service app itself and whitelisted packages, to only sockets that have had {@code protect()} + * service app itself and allowed packages, to only sockets that have had {@code protect()} * called on them. All non-VPN traffic is blocked via a {@code PROHIBIT} response from the * kernel. * @@ -1630,7 +1631,7 @@ public class Vpn { if (isNullOrLegacyVpn(mPackage)) { exemptedPackages = null; } else { - exemptedPackages = new ArrayList<>(mLockdownWhitelist); + exemptedPackages = new ArrayList<>(mLockdownAllowlist); exemptedPackages.add(mPackage); } final Set<UidRange> rangesToTellNetdToRemove = new ArraySet<>(mBlockedUidsAsToldToNetd); @@ -1675,7 +1676,7 @@ public class Vpn { * Tell netd to add or remove a list of {@link UidRange}s to the list of UIDs that are only * allowed to make connections through sockets that have had {@code protect()} called on them. * - * @param enforce {@code true} to add to the blacklist, {@code false} to remove. + * @param enforce {@code true} to add to the denylist, {@code false} to remove. * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is * {@code true}) or to remove. * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise, diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 397358b44362..dab8c7fc9d48 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -30,8 +30,6 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUST import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL; import static android.hardware.display.DisplayViewport.VIEWPORT_INTERNAL; import static android.hardware.display.DisplayViewport.VIEWPORT_VIRTUAL; -import static android.view.Surface.ROTATION_270; -import static android.view.Surface.ROTATION_90; import android.Manifest; import android.annotation.NonNull; @@ -46,7 +44,6 @@ import android.content.res.TypedArray; import android.database.ContentObserver; import android.graphics.ColorSpace; import android.graphics.Point; -import android.graphics.Rect; import android.hardware.SensorManager; import android.hardware.display.AmbientBrightnessDayStats; import android.hardware.display.BrightnessChangeEvent; @@ -104,7 +101,6 @@ import com.android.server.AnimationThread; import com.android.server.DisplayThread; import com.android.server.LocalServices; import com.android.server.SystemService; -import com.android.server.SystemService.TargetUser; import com.android.server.UiThread; import com.android.server.wm.SurfaceAnimationThread; import com.android.server.wm.WindowManagerInternal; @@ -1394,9 +1390,13 @@ public final class DisplayManagerService extends SystemService { } final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked(); - return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(token, new Rect(), - displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight(), - false /* useIdentityTransform */, 0 /* rotation */); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(token) + .setSize(displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight()) + .setUseIdentityTransform(true) + .setCaptureSecureLayers(true) + .build(); + return SurfaceControl.captureDisplay(captureArgs); } } @@ -1406,30 +1406,11 @@ public final class DisplayManagerService extends SystemService { if (token == null) { return null; } - final LogicalDisplay logicalDisplay = mLogicalDisplays.get(displayId); - if (logicalDisplay == null) { - return null; - } - - final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked(); - // Takes screenshot based on current device orientation. - final Display display = DisplayManagerGlobal.getInstance() - .getRealDisplay(displayId); - if (display == null) { - return null; - } - final Point displaySize = new Point(); - display.getRealSize(displaySize); - - int rotation = displayInfo.rotation; - // TODO (b/153382624) : This workaround solution would be removed after - // SurfaceFlinger fixes the inconsistency with rotation direction issue. - if (rotation == ROTATION_90 || rotation == ROTATION_270) { - rotation = (rotation == ROTATION_90) ? ROTATION_270 : ROTATION_90; - } - return SurfaceControl.screenshotToBuffer(token, new Rect(), displaySize.x, - displaySize.y, false /* useIdentityTransform */, rotation /* rotation */); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(token) + .build(); + return SurfaceControl.captureDisplay(captureArgs); } } diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java index 7bbcdaa2d473..6672daa6f17a 100644 --- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java +++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java @@ -949,7 +949,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem if (debug) { Slog.d(mTag, "Eagerly recreating service for user " + userId); } - getServiceForUserLocked(userId); + updateCachedServiceLocked(userId); } } onServicePackageRestartedLocked(userId); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java index 05cf40a091b6..3ac95d71de3d 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java @@ -178,7 +178,7 @@ public abstract class InputMethodManagerInternal { }; /** - * @return Global instance if exists. Otherwise, a dummy no-op instance. + * @return Global instance if exists. Otherwise, a fallback no-op instance. */ @NonNull public static InputMethodManagerInternal get() { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 3cd70fecbf3d..85a4515d46a0 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2213,8 +2213,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * @param client {@link android.os.Binder} proxy that is associated with the singleton instance * of {@link android.view.inputmethod.InputMethodManager} that runs on the client * process - * @param inputContext communication channel for the dummy - * {@link android.view.inputmethod.InputConnection} + * @param inputContext communication channel for the fallback {@link InputConnection} * @param selfReportedDisplayId self-reported display ID to which the client is associated. * Whether the client is still allowed to access to this display * or not needs to be evaluated every time the client interacts diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index 937514ca9139..b518eb1ab6d0 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -1663,7 +1663,7 @@ public final class MultiClientInputMethodManagerService { } if (editorInfo == null) { - // So-called dummy InputConnection scenario. For app compatibility, we still + // So-called fallback InputConnection scenario. For app compatibility, we still // notify this to the IME. switch (clientInfo.mState) { case InputMethodClientState.READY_TO_SEND_FIRST_BIND_RESULT: diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java index d4f8c7e855b9..c3532a84c42d 100644 --- a/services/core/java/com/android/server/location/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/LocationProviderManager.java @@ -1615,7 +1615,7 @@ class LocationProviderManager extends case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF: // fall through case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF: - updateService(); + updateRegistrations(registration -> true); break; default: break; diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index 8004ec70aaf3..850cf7f4b7ce 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -49,8 +49,6 @@ import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.PowerManager; -import android.os.PowerManager.ServiceType; -import android.os.PowerSaveState; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -486,10 +484,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements deviceIdleService.unregisterStationaryListener( mDeviceIdleStationaryListener); } - // Intentional fall-through. - case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED: - case Intent.ACTION_SCREEN_OFF: - case Intent.ACTION_SCREEN_ON: // Call updateLowPowerMode on handler thread so it's always called from the // same thread. mHandler.sendEmptyMessage(UPDATE_LOW_POWER_MODE); @@ -554,15 +548,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private void updateLowPowerMode() { // Disable GPS if we are in device idle mode and the device is stationary. boolean disableGpsForPowerManager = mPowerManager.isDeviceIdleMode() && mIsDeviceStationary; - final PowerSaveState result = mPowerManager.getPowerSaveState(ServiceType.LOCATION); - switch (result.locationMode) { - case PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF: - case PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF: - // If we are in battery saver mode and the screen is off, disable GPS. - disableGpsForPowerManager |= - result.batterySaverEnabled && !mPowerManager.isInteractive(); - break; - } if (disableGpsForPowerManager != mDisableGpsForPowerManager) { mDisableGpsForPowerManager = disableGpsForPowerManager; updateEnabled(); @@ -1959,10 +1944,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ALARM_WAKEUP); intentFilter.addAction(ALARM_TIMEOUT); - intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); - intentFilter.addAction(Intent.ACTION_SCREEN_OFF); - intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); intentFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index e2f70e320cb8..eb4ab1ceac28 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -1937,7 +1937,8 @@ public class MediaSessionService extends SystemService implements Monitor { // Context#getPackageName() for getting package name that matches with the PID/UID, // but it doesn't tell which package has created the MediaController, so useless. return hasMediaControlPermission(controllerPid, controllerUid) - || hasEnabledNotificationListener(userId, controllerPackageName, uid); + || hasEnabledNotificationListener( + userId, controllerPackageName, controllerUid); } finally { Binder.restoreCallingIdentity(token); } @@ -2001,21 +2002,21 @@ public class MediaSessionService extends SystemService implements Monitor { return resolvedUserId; } - private boolean hasEnabledNotificationListener(int resolvedUserId, String packageName, - int uid) { - // TODO: revisit this checking code - // You may not access another user's content as an enabled listener. - final int userId = UserHandle.getUserHandleForUid(resolvedUserId).getIdentifier(); - if (resolvedUserId != userId) { + private boolean hasEnabledNotificationListener(int callingUserId, + String controllerPackageName, int controllerUid) { + int controllerUserId = UserHandle.getUserHandleForUid(controllerUid).getIdentifier(); + if (callingUserId != controllerUserId) { + // Enabled notification listener only works within the same user. return false; } - if (mNotificationManager.hasEnabledNotificationListener(packageName, - UserHandle.getUserHandleForUid(uid))) { + + if (mNotificationManager.hasEnabledNotificationListener(controllerPackageName, + UserHandle.getUserHandleForUid(controllerUid))) { return true; } if (DEBUG) { - Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled " - + "notification listener"); + Log.d(TAG, controllerPackageName + " (uid=" + controllerUid + + ") doesn't have an enabled notification listener"); } return false; } diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java index 3bd18f9a360f..006d78e4a648 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java +++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java @@ -70,9 +70,9 @@ public class NetworkPolicyLogger { static final int NTWK_BLOCKED_POWER = 0; static final int NTWK_ALLOWED_NON_METERED = 1; - static final int NTWK_BLOCKED_BLACKLIST = 2; - static final int NTWK_ALLOWED_WHITELIST = 3; - static final int NTWK_ALLOWED_TMP_WHITELIST = 4; + static final int NTWK_BLOCKED_DENYLIST = 2; + static final int NTWK_ALLOWED_ALLOWLIST = 3; + static final int NTWK_ALLOWED_TMP_ALLOWLIST = 4; static final int NTWK_BLOCKED_BG_RESTRICT = 5; static final int NTWK_ALLOWED_DEFAULT = 6; static final int NTWK_ALLOWED_SYSTEM = 7; @@ -269,12 +269,12 @@ public class NetworkPolicyLogger { return "blocked by power restrictions"; case NTWK_ALLOWED_NON_METERED: return "allowed on unmetered network"; - case NTWK_BLOCKED_BLACKLIST: - return "blacklisted on metered network"; - case NTWK_ALLOWED_WHITELIST: - return "whitelisted on metered network"; - case NTWK_ALLOWED_TMP_WHITELIST: - return "temporary whitelisted on metered network"; + case NTWK_BLOCKED_DENYLIST: + return "denylisted on metered network"; + case NTWK_ALLOWED_ALLOWLIST: + return "allowlisted on metered network"; + case NTWK_ALLOWED_TMP_ALLOWLIST: + return "temporary allowlisted on metered network"; case NTWK_BLOCKED_BG_RESTRICT: return "blocked when background is restricted"; case NTWK_ALLOWED_DEFAULT: diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index d6557f6410ec..295143e76235 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -101,13 +101,13 @@ import static com.android.internal.util.XmlUtils.writeIntAttribute; import static com.android.internal.util.XmlUtils.writeLongAttribute; import static com.android.internal.util.XmlUtils.writeStringAttribute; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; +import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_ALLOWLIST; import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_DEFAULT; import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_NON_METERED; import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_SYSTEM; -import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_TMP_WHITELIST; -import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_WHITELIST; +import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_TMP_ALLOWLIST; import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BG_RESTRICT; -import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BLACKLIST; +import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_DENYLIST; import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_POWER; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED; @@ -507,7 +507,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * UIDs that have been initially white-listed by system to avoid restricted background. */ @GuardedBy("mUidRulesFirstLock") - private final SparseBooleanArray mDefaultRestrictBackgroundWhitelistUids = + private final SparseBooleanArray mDefaultRestrictBackgroundAllowlistUids = new SparseBooleanArray(); /** @@ -515,7 +515,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * but later revoked by user. */ @GuardedBy("mUidRulesFirstLock") - private final SparseBooleanArray mRestrictBackgroundWhitelistRevokedUids = + private final SparseBooleanArray mRestrictBackgroundAllowlistRevokedUids = new SparseBooleanArray(); /** Set of ifaces that are metered. */ @@ -582,7 +582,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") private final SparseBooleanArray mInternetPermissionMap = new SparseBooleanArray(); - // TODO: keep whitelist of system-critical services that should never have + // TODO: keep allowlist of system-critical services that should never have // rules enforced, such as system, phone, and radio UIDs. // TODO: migrate notifications to SystemUI @@ -668,26 +668,26 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** - * Whitelists pre-defined apps for restrict background, but only if the user didn't already - * revoke the whitelist. + * Allows pre-defined apps for restrict background, but only if the user didn't already + * revoked them. * - * @return whether any uid has been whitelisted. + * @return whether any uid has been allowlisted. */ @GuardedBy("mUidRulesFirstLock") - boolean addDefaultRestrictBackgroundWhitelistUidsUL() { + boolean addDefaultRestrictBackgroundAllowlistUidsUL() { final List<UserInfo> users = mUserManager.getUsers(); final int numberUsers = users.size(); boolean changed = false; for (int i = 0; i < numberUsers; i++) { final UserInfo user = users.get(i); - changed = addDefaultRestrictBackgroundWhitelistUidsUL(user.id) || changed; + changed = addDefaultRestrictBackgroundAllowlistUidsUL(user.id) || changed; } return changed; } @GuardedBy("mUidRulesFirstLock") - private boolean addDefaultRestrictBackgroundWhitelistUidsUL(int userId) { + private boolean addDefaultRestrictBackgroundAllowlistUidsUL(int userId) { final SystemConfig sysConfig = SystemConfig.getInstance(); final PackageManager pm = mContext.getPackageManager(); final ArraySet<String> allowDataUsage = sysConfig.getAllowInDataUsageSave(); @@ -695,7 +695,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (int i = 0; i < allowDataUsage.size(); i++) { final String pkg = allowDataUsage.valueAt(i); if (LOGD) - Slog.d(TAG, "checking restricted background whitelisting for package " + pkg + Slog.d(TAG, "checking restricted background allowlisting for package " + pkg + " and user " + userId); final ApplicationInfo app; try { @@ -706,20 +706,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { continue; } if (!app.isPrivilegedApp()) { - Slog.e(TAG, "addDefaultRestrictBackgroundWhitelistUidsUL(): " + Slog.e(TAG, "addDefaultRestrictBackgroundAllowlistUidsUL(): " + "skipping non-privileged app " + pkg); continue; } final int uid = UserHandle.getUid(userId, app.uid); - mDefaultRestrictBackgroundWhitelistUids.append(uid, true); + mDefaultRestrictBackgroundAllowlistUids.append(uid, true); if (LOGD) Slog.d(TAG, "Adding uid " + uid + " (user " + userId + ") to default restricted " - + "background whitelist. Revoked status: " - + mRestrictBackgroundWhitelistRevokedUids.get(uid)); - if (!mRestrictBackgroundWhitelistRevokedUids.get(uid)) { + + "background allowlist. Revoked status: " + + mRestrictBackgroundAllowlistRevokedUids.get(uid)); + if (!mRestrictBackgroundAllowlistRevokedUids.get(uid)) { if (LOGD) Slog.d(TAG, "adding default package " + pkg + " (uid " + uid + " for user " - + userId + ") to restrict background whitelist"); + + userId + ") to restrict background allowlist"); setUidPolicyUncheckedUL(uid, POLICY_ALLOW_METERED_BACKGROUND, false); changed = true; } @@ -799,7 +799,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } }); - if (addDefaultRestrictBackgroundWhitelistUidsUL()) { + if (addDefaultRestrictBackgroundAllowlistUidsUL()) { writePolicyAL(); } @@ -1005,14 +1005,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case ACTION_USER_ADDED: synchronized (mUidRulesFirstLock) { // Remove any persistable state for the given user; both cleaning up after a - // USER_REMOVED, and one last sanity check during USER_ADDED + // USER_REMOVED, and one last check during USER_ADDED removeUserStateUL(userId, true, false); // Removing outside removeUserStateUL since that can also be called when // user resets app preferences. mMeteredRestrictedUids.remove(userId); if (action == ACTION_USER_ADDED) { - // Add apps that are whitelisted by default. - addDefaultRestrictBackgroundWhitelistUidsUL(userId); + // Add apps that are allowlisted by default. + addDefaultRestrictBackgroundAllowlistUidsUL(userId); } // Update global restrict for that user synchronized (mNetworkPoliciesSecondLock) { @@ -2196,12 +2196,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { in.setInput(fis, StandardCharsets.UTF_8.name()); // Must save the <restrict-background> tags and convert them to <uid-policy> later, - // to skip UIDs that were explicitly blacklisted. - final SparseBooleanArray whitelistedRestrictBackground = new SparseBooleanArray(); + // to skip UIDs that were explicitly denylisted. + final SparseBooleanArray allowlistedRestrictBackground = new SparseBooleanArray(); int type; int version = VERSION_INIT; - boolean insideWhitelist = false; + boolean insideAllowlist = false; while ((type = in.next()) != END_DOCUMENT) { final String tag = in.getName(); if (type == START_TAG) { @@ -2340,28 +2340,28 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring"); } } else if (TAG_WHITELIST.equals(tag)) { - insideWhitelist = true; - } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) { + insideAllowlist = true; + } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) { final int uid = readIntAttribute(in, ATTR_UID); - whitelistedRestrictBackground.append(uid, true); - } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) { + allowlistedRestrictBackground.append(uid, true); + } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) { final int uid = readIntAttribute(in, ATTR_UID); - mRestrictBackgroundWhitelistRevokedUids.put(uid, true); + mRestrictBackgroundAllowlistRevokedUids.put(uid, true); } } else if (type == END_TAG) { if (TAG_WHITELIST.equals(tag)) { - insideWhitelist = false; + insideAllowlist = false; } } } - final int size = whitelistedRestrictBackground.size(); + final int size = allowlistedRestrictBackground.size(); for (int i = 0; i < size; i++) { - final int uid = whitelistedRestrictBackground.keyAt(i); + final int uid = allowlistedRestrictBackground.keyAt(i); final int policy = mUidPolicy.get(uid, POLICY_NONE); if ((policy & POLICY_REJECT_METERED_BACKGROUND) != 0) { - Slog.w(TAG, "ignoring restrict-background-whitelist for " + uid + Slog.w(TAG, "ignoring restrict-background-allowlist for " + uid + " because its policy is " + uidPoliciesToString(policy)); continue; } @@ -2533,13 +2533,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { out.endTag(null, TAG_POLICY_LIST); - // write all whitelists + // write all allowlists out.startTag(null, TAG_WHITELIST); - // revoked restrict background whitelist - int size = mRestrictBackgroundWhitelistRevokedUids.size(); + // revoked restrict background allowlist + int size = mRestrictBackgroundAllowlistRevokedUids.size(); for (int i = 0; i < size; i++) { - final int uid = mRestrictBackgroundWhitelistRevokedUids.keyAt(i); + final int uid = mRestrictBackgroundAllowlistRevokedUids.keyAt(i); out.startTag(null, TAG_REVOKED_RESTRICT_BACKGROUND); writeIntAttribute(out, ATTR_UID, uid); out.endTag(null, TAG_REVOKED_RESTRICT_BACKGROUND); @@ -2619,21 +2619,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { setUidPolicyUncheckedUL(uid, policy, false); final boolean notifyApp; - if (!isUidValidForWhitelistRulesUL(uid)) { + if (!isUidValidForAllowlistRulesUL(uid)) { notifyApp = false; } else { - final boolean wasBlacklisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND; - final boolean isBlacklisted = policy == POLICY_REJECT_METERED_BACKGROUND; - final boolean wasWhitelisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND; - final boolean isWhitelisted = policy == POLICY_ALLOW_METERED_BACKGROUND; - final boolean wasBlocked = wasBlacklisted || (mRestrictBackground && !wasWhitelisted); - final boolean isBlocked = isBlacklisted || (mRestrictBackground && !isWhitelisted); - if ((wasWhitelisted && (!isWhitelisted || isBlacklisted)) - && mDefaultRestrictBackgroundWhitelistUids.get(uid) - && !mRestrictBackgroundWhitelistRevokedUids.get(uid)) { + final boolean wasDenylisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND; + final boolean isDenylisted = policy == POLICY_REJECT_METERED_BACKGROUND; + final boolean wasAllowlisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND; + final boolean isAllowlisted = policy == POLICY_ALLOW_METERED_BACKGROUND; + final boolean wasBlocked = wasDenylisted || (mRestrictBackground && !wasAllowlisted); + final boolean isBlocked = isDenylisted || (mRestrictBackground && !isAllowlisted); + if ((wasAllowlisted && (!isAllowlisted || isDenylisted)) + && mDefaultRestrictBackgroundAllowlistUids.get(uid) + && !mRestrictBackgroundAllowlistRevokedUids.get(uid)) { if (LOGD) - Slog.d(TAG, "Adding uid " + uid + " to revoked restrict background whitelist"); - mRestrictBackgroundWhitelistRevokedUids.append(uid, true); + Slog.d(TAG, "Adding uid " + uid + " to revoked restrict background allowlist"); + mRestrictBackgroundAllowlistRevokedUids.append(uid, true); } notifyApp = wasBlocked != isBlocked; } @@ -2700,11 +2700,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mLogger.removingUserState(userId); boolean changed = false; - // Remove entries from revoked default restricted background UID whitelist - for (int i = mRestrictBackgroundWhitelistRevokedUids.size() - 1; i >= 0; i--) { - final int uid = mRestrictBackgroundWhitelistRevokedUids.keyAt(i); + // Remove entries from revoked default restricted background UID allowlist + for (int i = mRestrictBackgroundAllowlistRevokedUids.size() - 1; i >= 0; i--) { + final int uid = mRestrictBackgroundAllowlistRevokedUids.keyAt(i); if (UserHandle.getUserId(uid) == userId) { - mRestrictBackgroundWhitelistRevokedUids.removeAt(i); + mRestrictBackgroundAllowlistRevokedUids.removeAt(i); changed = true; } } @@ -2913,7 +2913,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Slog.d(TAG, "setRestrictBackgroundUL(): " + restrictBackground + "; reason: " + reason); final boolean oldRestrictBackground = mRestrictBackground; mRestrictBackground = restrictBackground; - // Must whitelist foreground apps before turning data saver mode on. + // Must allowlist foreground apps before turning data saver mode on. // TODO: there is no need to iterate through all apps here, just those in the foreground, // so it could call AM to get the UIDs of such apps, and iterate through them instead. updateRulesForRestrictBackgroundUL(); @@ -2966,7 +2966,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Binder.restoreCallingIdentity(token); } if (policy == POLICY_REJECT_METERED_BACKGROUND) { - // App is blacklisted. + // App is denylisted. return RESTRICT_BACKGROUND_STATUS_ENABLED; } if (!mRestrictBackground) { @@ -3543,25 +3543,25 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.decreaseIndent(); } - size = mDefaultRestrictBackgroundWhitelistUids.size(); + size = mDefaultRestrictBackgroundAllowlistUids.size(); if (size > 0) { - fout.println("Default restrict background whitelist uids:"); + fout.println("Default restrict background allowlist uids:"); fout.increaseIndent(); for (int i = 0; i < size; i++) { fout.print("UID="); - fout.print(mDefaultRestrictBackgroundWhitelistUids.keyAt(i)); + fout.print(mDefaultRestrictBackgroundAllowlistUids.keyAt(i)); fout.println(); } fout.decreaseIndent(); } - size = mRestrictBackgroundWhitelistRevokedUids.size(); + size = mRestrictBackgroundAllowlistRevokedUids.size(); if (size > 0) { - fout.println("Default restrict background whitelist uids revoked by users:"); + fout.println("Default restrict background allowlist uids revoked by users:"); fout.increaseIndent(); for (int i = 0; i < size; i++) { fout.print("UID="); - fout.print(mRestrictBackgroundWhitelistRevokedUids.keyAt(i)); + fout.print(mRestrictBackgroundAllowlistRevokedUids.keyAt(i)); fout.println(); } fout.decreaseIndent(); @@ -3882,7 +3882,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") void updateRuleForAppIdleUL(int uid) { - if (!isUidValidForBlacklistRulesUL(uid)) return; + if (!isUidValidForDenylistRulesUL(uid)) return; if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRuleForAppIdleUL: " + uid ); @@ -3915,13 +3915,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final SparseIntArray blockedUids = new SparseIntArray(); for (int i = 0; i < ruleCount; i++) { final int uid = mUidFirewallStandbyRules.keyAt(i); - if (!isUidValidForBlacklistRulesUL(uid)) { + if (!isUidValidForDenylistRulesUL(uid)) { continue; } int oldRules = mUidRules.get(uid); if (enableChain) { // Chain wasn't enabled before and the other power-related - // chains are whitelists, so we can clear the + // chains are allowlists, so we can clear the // MASK_ALL_NETWORKS part of the rules and re-inform listeners if // the effective rules result in blocking network access. oldRules &= MASK_METERED_NETWORKS; @@ -4079,10 +4079,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // TODO: the MEDIA / DRM restriction might not be needed anymore, in which case both // methods below could be merged into a isUidValidForRules() method. @GuardedBy("mUidRulesFirstLock") - private boolean isUidValidForBlacklistRulesUL(int uid) { + private boolean isUidValidForDenylistRulesUL(int uid) { // allow rules on specific system services, and any apps if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID - || isUidValidForWhitelistRulesUL(uid)) { + || isUidValidForAllowlistRulesUL(uid)) { return true; } @@ -4090,7 +4090,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @GuardedBy("mUidRulesFirstLock") - private boolean isUidValidForWhitelistRulesUL(int uid) { + private boolean isUidValidForAllowlistRulesUL(int uid) { return UserHandle.isApp(uid) && hasInternetPermissionUL(uid); } @@ -4235,23 +4235,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** * Applies network rules to bandwidth controllers based on process state and user-defined - * restrictions (blacklist / whitelist). + * restrictions (allowlist / denylist). * * <p> * {@code netd} defines 3 firewall chains that govern whether an app has access to metered * networks: * <ul> - * <li>@{code bw_penalty_box}: UIDs added to this chain do not have access (blacklist). - * <li>@{code bw_happy_box}: UIDs added to this chain have access (whitelist), unless they're - * also blacklisted. + * <li>@{code bw_penalty_box}: UIDs added to this chain do not have access (denylist). + * <li>@{code bw_happy_box}: UIDs added to this chain have access (allowlist), unless they're + * also denylisted. * <li>@{code bw_data_saver}: when enabled (through {@link #setRestrictBackground(boolean)}), - * no UIDs other than those whitelisted will have access. + * no UIDs other than those allowlisted will have access. * <ul> * * <p>The @{code bw_penalty_box} and @{code bw_happy_box} are primarily managed through the - * {@link #setUidPolicy(int, int)} and {@link #addRestrictBackgroundWhitelistedUid(int)} / - * {@link #removeRestrictBackgroundWhitelistedUid(int)} methods (for blacklist and whitelist - * respectively): these methods set the proper internal state (blacklist / whitelist), then call + * {@link #setUidPolicy(int, int)} and {@link #addRestrictBackgroundAllowlistedUid(int)} / + * {@link #removeRestrictBackgroundDenylistedUid(int)} methods (for denylist and allowlist + * respectively): these methods set the proper internal state (denylist / allowlist), then call * this ({@link #updateRulesForDataUsageRestrictionsUL(int)}) to propagate the rules to * {@link INetworkManagementService}, but this method should also be called in events (like * Data Saver Mode flips or UID state changes) that might affect the foreground app, since the @@ -4260,7 +4260,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * <ul> * <li>When Data Saver mode is on, the foreground app should be temporarily added to * {@code bw_happy_box} before the @{code bw_data_saver} chain is enabled. - * <li>If the foreground app is blacklisted by the user, it should be temporarily removed from + * <li>If the foreground app is denylisted by the user, it should be temporarily removed from * {@code bw_penalty_box}. * <li>When the app leaves foreground state, the temporary changes above should be reverted. * </ul> @@ -4285,7 +4285,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } private void updateRulesForDataUsageRestrictionsULInner(int uid) { - if (!isUidValidForWhitelistRulesUL(uid)) { + if (!isUidValidForAllowlistRulesUL(uid)) { if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid); return; } @@ -4295,8 +4295,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid); final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid); - final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; - final boolean isWhitelisted = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0; + final boolean isDenylisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; + final boolean isAllowlisted = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0; final int oldRule = oldUidRules & MASK_METERED_NETWORKS; int newRule = RULE_NONE; @@ -4304,15 +4304,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (isRestrictedByAdmin) { newRule = RULE_REJECT_METERED; } else if (isForeground) { - if (isBlacklisted || (mRestrictBackground && !isWhitelisted)) { + if (isDenylisted || (mRestrictBackground && !isAllowlisted)) { newRule = RULE_TEMPORARY_ALLOW_METERED; - } else if (isWhitelisted) { + } else if (isAllowlisted) { newRule = RULE_ALLOW_METERED; } } else { - if (isBlacklisted) { + if (isDenylisted) { newRule = RULE_REJECT_METERED; - } else if (mRestrictBackground && isWhitelisted) { + } else if (mRestrictBackground && isAllowlisted) { newRule = RULE_ALLOW_METERED; } } @@ -4321,8 +4321,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (LOGV) { Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")" + ": isForeground=" +isForeground - + ", isBlacklisted=" + isBlacklisted - + ", isWhitelisted=" + isWhitelisted + + ", isDenylisted=" + isDenylisted + + ", isAllowlisted=" + isAllowlisted + ", isRestrictedByAdmin=" + isRestrictedByAdmin + ", oldRule=" + uidRulesToString(oldRule) + ", newRule=" + uidRulesToString(newRule) @@ -4339,49 +4339,49 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Second step: apply bw changes based on change of state. if (newRule != oldRule) { if (hasRule(newRule, RULE_TEMPORARY_ALLOW_METERED)) { - // Temporarily whitelist foreground app, removing from blacklist if necessary + // Temporarily allowlist foreground app, removing from denylist if necessary // (since bw_penalty_box prevails over bw_happy_box). - setMeteredNetworkWhitelist(uid, true); + setMeteredNetworkAllowlist(uid, true); // TODO: if statement below is used to avoid an unnecessary call to netd / iptables, // but ideally it should be just: - // setMeteredNetworkBlacklist(uid, isBlacklisted); - if (isBlacklisted) { - setMeteredNetworkBlacklist(uid, false); + // setMeteredNetworkDenylist(uid, isDenylisted); + if (isDenylisted) { + setMeteredNetworkDenylist(uid, false); } } else if (hasRule(oldRule, RULE_TEMPORARY_ALLOW_METERED)) { - // Remove temporary whitelist from app that is not on foreground anymore. + // Remove temporary allowlist from app that is not on foreground anymore. // TODO: if statements below are used to avoid unnecessary calls to netd / iptables, // but ideally they should be just: - // setMeteredNetworkWhitelist(uid, isWhitelisted); - // setMeteredNetworkBlacklist(uid, isBlacklisted); - if (!isWhitelisted) { - setMeteredNetworkWhitelist(uid, false); + // setMeteredNetworkAllowlist(uid, isAllowlisted); + // setMeteredNetworkDenylist(uid, isDenylisted); + if (!isAllowlisted) { + setMeteredNetworkAllowlist(uid, false); } - if (isBlacklisted || isRestrictedByAdmin) { - setMeteredNetworkBlacklist(uid, true); + if (isDenylisted || isRestrictedByAdmin) { + setMeteredNetworkDenylist(uid, true); } } else if (hasRule(newRule, RULE_REJECT_METERED) || hasRule(oldRule, RULE_REJECT_METERED)) { - // Flip state because app was explicitly added or removed to blacklist. - setMeteredNetworkBlacklist(uid, (isBlacklisted || isRestrictedByAdmin)); - if (hasRule(oldRule, RULE_REJECT_METERED) && isWhitelisted) { - // Since blacklist prevails over whitelist, we need to handle the special case - // where app is whitelisted and blacklisted at the same time (although such - // scenario should be blocked by the UI), then blacklist is removed. - setMeteredNetworkWhitelist(uid, isWhitelisted); + // Flip state because app was explicitly added or removed to denylist. + setMeteredNetworkDenylist(uid, (isDenylisted || isRestrictedByAdmin)); + if (hasRule(oldRule, RULE_REJECT_METERED) && isAllowlisted) { + // Since dneylist prevails over allowlist, we need to handle the special case + // where app is allowlisted and denylisted at the same time (although such + // scenario should be blocked by the UI), then denylist is removed. + setMeteredNetworkAllowlist(uid, isAllowlisted); } } else if (hasRule(newRule, RULE_ALLOW_METERED) || hasRule(oldRule, RULE_ALLOW_METERED)) { - // Flip state because app was explicitly added or removed to whitelist. - setMeteredNetworkWhitelist(uid, isWhitelisted); + // Flip state because app was explicitly added or removed to allowlist. + setMeteredNetworkAllowlist(uid, isAllowlisted); } else { // All scenarios should have been covered above. Log.wtf(TAG, "Unexpected change of metered UID state for " + uid + ": foreground=" + isForeground - + ", whitelisted=" + isWhitelisted - + ", blacklisted=" + isBlacklisted + + ", allowlisted=" + isAllowlisted + + ", denylisted=" + isDenylisted + ", isRestrictedByAdmin=" + isRestrictedByAdmin + ", newRule=" + uidRulesToString(newUidRules) + ", oldRule=" + uidRulesToString(oldUidRules)); @@ -4397,7 +4397,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * listeners in case of change. * <p> * There are 3 power-related rules that affects whether an app has background access on - * non-metered networks, and when the condition applies and the UID is not whitelisted for power + * non-metered networks, and when the condition applies and the UID is not allowlisted for power * restriction, it's added to the equivalent firewall chain: * <ul> * <li>App is idle: {@code fw_standby} firewall chain. @@ -4406,7 +4406,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * </ul> * <p> * This method updates the power-related part of the {@link #mUidRules} for a given uid based on - * these modes, the UID process state (foreground or not), and the UIDwhitelist state. + * these modes, the UID process state (foreground or not), and the UID allowlist state. * <p> * <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}. */ @@ -4450,7 +4450,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules, boolean isUidIdle) { - if (!isUidValidForBlacklistRulesUL(uid)) { + if (!isUidValidForDenylistRulesUL(uid)) { if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid); return RULE_NONE; } @@ -4859,23 +4859,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - private void setMeteredNetworkBlacklist(int uid, boolean enable) { - if (LOGV) Slog.v(TAG, "setMeteredNetworkBlacklist " + uid + ": " + enable); + private void setMeteredNetworkDenylist(int uid, boolean enable) { + if (LOGV) Slog.v(TAG, "setMeteredNetworkDenylist " + uid + ": " + enable); try { - mNetworkManager.setUidMeteredNetworkBlacklist(uid, enable); + mNetworkManager.setUidMeteredNetworkDenylist(uid, enable); } catch (IllegalStateException e) { - Log.wtf(TAG, "problem setting blacklist (" + enable + ") rules for " + uid, e); + Log.wtf(TAG, "problem setting denylist (" + enable + ") rules for " + uid, e); } catch (RemoteException e) { // ignored; service lives in system_server } } - private void setMeteredNetworkWhitelist(int uid, boolean enable) { - if (LOGV) Slog.v(TAG, "setMeteredNetworkWhitelist " + uid + ": " + enable); + private void setMeteredNetworkAllowlist(int uid, boolean enable) { + if (LOGV) Slog.v(TAG, "setMeteredNetworkAllowlist " + uid + ": " + enable); try { - mNetworkManager.setUidMeteredNetworkWhitelist(uid, enable); + mNetworkManager.setUidMeteredNetworkAllowlist(uid, enable); } catch (IllegalStateException e) { - Log.wtf(TAG, "problem setting whitelist (" + enable + ") rules for " + uid, e); + Log.wtf(TAG, "problem setting allowlist (" + enable + ") rules for " + uid, e); } catch (RemoteException e) { // ignored; service lives in system_server } @@ -4936,7 +4936,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** - * Add or remove a uid to the firewall blacklist for all network ifaces. + * Add or remove a uid to the firewall denylist for all network ifaces. */ private void setUidFirewallRule(int chain, int uid, int rule) { if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { @@ -4966,7 +4966,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** - * Add or remove a uid to the firewall blacklist for all network ifaces. + * Add or remove a uid to the firewall denylist for all network ifaces. */ @GuardedBy("mUidRulesFirstLock") private void enableFirewallChainUL(int chain, boolean enable) { @@ -4995,8 +4995,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT); mNetworkManager .setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT); - mNetworkManager.setUidMeteredNetworkWhitelist(uid, false); - mNetworkManager.setUidMeteredNetworkBlacklist(uid, false); + mNetworkManager.setUidMeteredNetworkAllowlist(uid, false); + mNetworkManager.setUidMeteredNetworkDenylist(uid, false); } catch (IllegalStateException e) { Log.wtf(TAG, "problem resetting firewall uid rules for " + uid, e); } catch (RemoteException e) { @@ -5189,13 +5189,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { reason = NTWK_ALLOWED_NON_METERED; } else if (hasRule(uidRules, RULE_REJECT_METERED)) { - reason = NTWK_BLOCKED_BLACKLIST; + reason = NTWK_BLOCKED_DENYLIST; } else if (hasRule(uidRules, RULE_ALLOW_METERED)) { - reason = NTWK_ALLOWED_WHITELIST; + reason = NTWK_ALLOWED_ALLOWLIST; } else if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) { - reason = NTWK_ALLOWED_TMP_WHITELIST; + reason = NTWK_ALLOWED_TMP_ALLOWLIST; } else if (isBackgroundRestricted) { reason = NTWK_BLOCKED_BG_RESTRICT; @@ -5208,13 +5208,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { switch(reason) { case NTWK_ALLOWED_DEFAULT: case NTWK_ALLOWED_NON_METERED: - case NTWK_ALLOWED_TMP_WHITELIST: - case NTWK_ALLOWED_WHITELIST: + case NTWK_ALLOWED_TMP_ALLOWLIST: + case NTWK_ALLOWED_ALLOWLIST: case NTWK_ALLOWED_SYSTEM: blocked = false; break; case NTWK_BLOCKED_POWER: - case NTWK_BLOCKED_BLACKLIST: + case NTWK_BLOCKED_DENYLIST: case NTWK_BLOCKED_BG_RESTRICT: blocked = true; break; @@ -5234,7 +5234,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { public void resetUserState(int userId) { synchronized (mUidRulesFirstLock) { boolean changed = removeUserStateUL(userId, false, true); - changed = addDefaultRestrictBackgroundWhitelistUidsUL(userId) || changed; + changed = addDefaultRestrictBackgroundAllowlistUidsUL(userId) || changed; if (changed) { synchronized (mNetworkPoliciesSecondLock) { writePolicyAL(); diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 840645edcb82..8af74631fb2e 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -613,6 +613,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements throw new IllegalArgumentException( "APEX files can only be installed as part of a staged session."); } + if (params.isMultiPackage) { + throw new IllegalArgumentException("A multi-session can't be set as APEX."); + } } if (params.isStaged && !isCalledBySystemOrShell(callingUid)) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ff9edd511e84..2807a1e4c081 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1637,7 +1637,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * If session should be sealed, then it's sealed to prevent further modification. * If the session can't be sealed then it's destroyed. * - * Additionally for staged APEX sessions read+validate the package and populate req'd fields. + * Additionally for staged APEX/APK sessions read+validate the package and populate req'd + * fields. * * <p> This is meant to be called after all of the sessions are loaded and added to * PackageInstallerService @@ -1670,6 +1671,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // APEX installations rely on certain fields to be populated after reboot. // E.g. mPackageName. validateApexInstallLocked(); + } else { + // Populate mPackageName for this APK session which is required by the staging + // manager to check duplicate apk-in-apex. + PackageInstallerSession parent = allSessions.get(mParentSessionId); + if (parent != null && parent.isStagedSessionReady()) { + validateApkInstallLocked(); + } } } catch (PackageManagerException e) { Slog.e(TAG, "Package not valid", e); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index a874f612e106..572892bd6ff5 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -103,7 +103,6 @@ import static android.os.incremental.IncrementalManager.isIncrementalPath; import static android.os.storage.StorageManager.FLAG_STORAGE_CE; import static android.os.storage.StorageManager.FLAG_STORAGE_DE; import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL; -import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED; import static com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE; @@ -365,7 +364,6 @@ import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.permission.BasePermission; import com.android.server.pm.permission.PermissionManagerService; import com.android.server.pm.permission.PermissionManagerServiceInternal; -import com.android.server.pm.permission.PermissionsState; import com.android.server.policy.PermissionPolicyInternal; import com.android.server.rollback.RollbackManagerInternal; import com.android.server.security.VerityUtils; @@ -1807,7 +1805,7 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { removeMessages(WRITE_SETTINGS); removeMessages(WRITE_PACKAGE_RESTRICTIONS); - mSettings.writeLPr(); + writeSettingsLPrTEMP(); mDirtyUsers.clear(); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); @@ -1827,6 +1825,7 @@ public class PackageManagerService extends IPackageManager.Stub Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mLock) { removeMessages(WRITE_PACKAGE_LIST); + mPermissionManager.writePermissionsStateToPackageSettingsTEMP(); mSettings.writePackageListLPr(msg.arg1); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); @@ -2232,7 +2231,7 @@ public class PackageManagerService extends IPackageManager.Stub sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, 0 /*flags*/, installerPackageName, null /*finishedReceiver*/, - updateUserIds, instantUserIds, null /* broadcastWhitelist */); + updateUserIds, instantUserIds, null /* broadcastAllowList */); } // if the required verifier is defined, but, is not the installer of record // for the package, it gets notified @@ -2242,7 +2241,7 @@ public class PackageManagerService extends IPackageManager.Stub sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, 0 /*flags*/, mRequiredVerifierPackage, null /*finishedReceiver*/, - updateUserIds, instantUserIds, null /* broadcastWhitelist */); + updateUserIds, instantUserIds, null /* broadcastAllowList */); } // If package installer is defined, notify package installer about new // app installed @@ -2250,7 +2249,7 @@ public class PackageManagerService extends IPackageManager.Stub sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/, mRequiredInstallerPackage, null /*finishedReceiver*/, - firstUserIds, instantUserIds, null /* broadcastWhitelist */); + firstUserIds, instantUserIds, null /* broadcastAllowList */); } // Send replaced for users that don't see the package for the first time @@ -2263,19 +2262,19 @@ public class PackageManagerService extends IPackageManager.Stub sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras, 0 /*flags*/, installerPackageName, null /*finishedReceiver*/, - updateUserIds, instantUserIds, null /*broadcastWhitelist*/); + updateUserIds, instantUserIds, null /*broadcastAllowList*/); } if (notifyVerifier) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras, 0 /*flags*/, mRequiredVerifierPackage, null /*finishedReceiver*/, - updateUserIds, instantUserIds, null /*broadcastWhitelist*/); + updateUserIds, instantUserIds, null /*broadcastAllowList*/); } sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null /*package*/, null /*extras*/, 0 /*flags*/, packageName /*targetPackage*/, null /*finishedReceiver*/, updateUserIds, instantUserIds, - null /*broadcastWhitelist*/); + null /*broadcastAllowList*/); } else if (launchedForRestore && !res.pkg.isSystem()) { // First-install and we did a restore, so we're responsible for the // first-launch broadcast. @@ -2507,7 +2506,7 @@ public class PackageManagerService extends IPackageManager.Stub } mSettings.onVolumeForgotten(fsUuid); - mSettings.writeLPr(); + writeSettingsLPrTEMP(); } } }; @@ -3427,6 +3426,7 @@ public class PackageManagerService extends IPackageManager.Stub + ((SystemClock.uptimeMillis()-startTime)/1000f) + " seconds"); + mPermissionManager.readPermissionsStateFromPackageSettingsTEMP(); // If the platform SDK has changed since the last time we booted, // we need to re-grant app permission to catch any new ones that // appear. This is really a hack, and means that apps can in some @@ -3544,7 +3544,7 @@ public class PackageManagerService extends IPackageManager.Stub // can downgrade to reader t.traceBegin("write settings"); - mSettings.writeLPr(); + writeSettingsLPrTEMP(); t.traceEnd(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); @@ -3748,7 +3748,7 @@ public class PackageManagerService extends IPackageManager.Stub Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e); } mPermissionManager.updatePermissions(pkg.getPackageName(), pkg); - mSettings.writeLPr(); + writeSettingsLPrTEMP(); } } catch (PackageManagerException e) { // Whoops! Something went very wrong; roll back to the stub and disable the package @@ -3759,9 +3759,8 @@ public class PackageManagerService extends IPackageManager.Stub // If we don't, installing the system package fails during scan enableSystemPackageLPw(stubPkg); } - installPackageFromSystemLIF(stubPkg.getCodePath(), - null /*allUserHandles*/, null /*origUserHandles*/, - null /*origPermissionsState*/, true /*writeSettings*/); + installPackageFromSystemLIF(stubPkg.getCodePath(), null /*allUserHandles*/, + null /*origUserHandles*/, true /*writeSettings*/); } catch (PackageManagerException pme) { // Serious WTF; we have to be able to install the stub Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(), @@ -3775,7 +3774,7 @@ public class PackageManagerService extends IPackageManager.Stub stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android"); } - mSettings.writeLPr(); + writeSettingsLPrTEMP(); } } return false; @@ -14627,7 +14626,7 @@ public class PackageManagerService extends IPackageManager.Stub private void sendFirstLaunchBroadcast(String pkgName, String installerPkg, int[] userIds, int[] instantUserIds) { sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0, - installerPkg, null, userIds, instantUserIds, null /* broadcastWhitelist */); + installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */); } private abstract class HandlerParams { @@ -16263,7 +16262,7 @@ public class PackageManagerService extends IPackageManager.Stub res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); //to update install status Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings"); - mSettings.writeLPr(); + writeSettingsLPrTEMP(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } @@ -18730,14 +18729,14 @@ public class PackageManagerService extends IPackageManager.Stub packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage, extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList); packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0, - removedPackage, null, null, null, null /* broadcastWhitelist */); + removedPackage, null, null, null, null /* broadcastAllowList */); if (installerPackageName != null) { packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage, extras, 0 /*flags*/, - installerPackageName, null, null, null, null /* broadcastWhitelist */); + installerPackageName, null, null, null, null /* broadcastAllowList */); packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage, extras, 0 /*flags*/, - installerPackageName, null, null, null, null /* broadcastWhitelist */); + installerPackageName, null, null, null, null /* broadcastAllowList */); } } @@ -18863,29 +18862,11 @@ public class PackageManagerService extends IPackageManager.Stub if (outInfo != null) { outInfo.removedAppId = removedAppId; } - mPermissionManager.updatePermissions(deletedPs.name, null); - if (deletedPs.sharedUser != null) { - // Remove permissions associated with package. Since runtime - // permissions are per user we have to kill the removed package - // or packages running under the shared user of the removed - // package if revoking the permissions requested only by the removed - // package is successful and this causes a change in gids. - boolean shouldKill = false; - for (int userId : UserManagerService.getInstance().getUserIds()) { - final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs, - userId); - shouldKill |= userIdToKill == UserHandle.USER_ALL - || userIdToKill >= UserHandle.USER_SYSTEM; - } - // If gids changed, kill all affected packages. - if (shouldKill) { - mHandler.post(() -> { - // This has to happen with no lock held. - killApplication(deletedPs.name, deletedPs.appId, - KILL_APP_REASON_GIDS_CHANGED); - }); - } + if ((deletedPs.sharedUser == null || deletedPs.sharedUser.packages.size() == 0) + && !isUpdatedSystemApp(deletedPs)) { + mPermissionManager.removePermissionsStateTEMP(removedAppId); } + mPermissionManager.updatePermissions(deletedPs.name, null); clearPackagePreferredActivitiesLPw( deletedPs.name, changedUsers, UserHandle.USER_ALL); } @@ -18919,7 +18900,7 @@ public class PackageManagerService extends IPackageManager.Stub // can downgrade to reader if (writeSettings) { // Save settings now - mSettings.writeLPr(); + writeSettingsLPrTEMP(); } if (installedStateChanged) { mSettings.writeKernelMappingLPr(deletedPs); @@ -19006,8 +18987,7 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs); try { installPackageFromSystemLIF(disabledPs.getCodePathString(), allUserHandles, - outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(), - writeSettings); + outInfo == null ? null : outInfo.origUsers, writeSettings); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": " + e.getMessage()); @@ -19038,9 +19018,8 @@ public class PackageManagerService extends IPackageManager.Stub * Installs a package that's already on the system partition. */ private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString, - @Nullable int[] allUserHandles, @Nullable int[] origUserHandles, - @Nullable PermissionsState origPermissionState, boolean writeSettings) - throws PackageManagerException { + @Nullable int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings) + throws PackageManagerException { final File codePath = new File(codePathString); @ParseFlags int parseFlags = mDefParseFlags @@ -19077,12 +19056,8 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName()); - // Propagate the permissions state as we do not want to drop on the floor - // runtime permissions. The update permissions method below will take - // care of removing obsolete permissions and grant install permissions. - if (origPermissionState != null) { - ps.getPermissionsState().copyFrom(origPermissionState); - } + // The update permissions method below will take care of removing obsolete permissions + // and granting install permissions. mPermissionManager.updatePermissions(pkg.getPackageName(), pkg); final boolean applyUserRestrictions @@ -19116,7 +19091,7 @@ public class PackageManagerService extends IPackageManager.Stub } // can downgrade to reader here if (writeSettings) { - mSettings.writeLPr(); + writeSettingsLPrTEMP(); } } return pkg; @@ -19190,7 +19165,7 @@ public class PackageManagerService extends IPackageManager.Stub } else { ps.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER; } - mSettings.writeLPr(); + writeSettingsLPrTEMP(); } return true; } @@ -20382,7 +20357,7 @@ public class PackageManagerService extends IPackageManager.Stub (parser1, userId1) -> { synchronized (mLock) { mSettings.readAllDomainVerificationsLPr(parser1, userId1); - mSettings.writeLPr(); + writeSettingsLPrTEMP(); } }); } catch (Exception e) { @@ -21733,6 +21708,8 @@ public class PackageManagerService extends IPackageManager.Stub protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return; + mPermissionManager.writePermissionsStateToPackageSettingsTEMP(); + DumpState dumpState = new DumpState(); boolean fullPreferred = false; boolean checkin = false; @@ -21928,7 +21905,7 @@ public class PackageManagerService extends IPackageManager.Stub dumpState.setDump(DumpState.DUMP_SERVICE_PERMISSIONS); } else if ("write".equals(cmd)) { synchronized (mLock) { - mSettings.writeLPr(); + writeSettingsLPrTEMP(); pw.println("Settings written."); return; } @@ -22646,7 +22623,7 @@ public class PackageManagerService extends IPackageManager.Stub // Yay, everything is now upgraded ver.forceCurrent(); - mSettings.writeLPr(); + writeSettingsLPrTEMP(); } for (PackageFreezer freezer : freezers) { @@ -22696,7 +22673,7 @@ public class PackageManagerService extends IPackageManager.Stub AttributeCache.instance().removePackage(ps.name); } - mSettings.writeLPr(); + writeSettingsLPrTEMP(); } } @@ -23575,6 +23552,8 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { mDirtyUsers.remove(userId); mUserNeedsBadging.delete(userId); + mPermissionManager.onUserRemoved(userId); + mPermissionManager.writePermissionsStateToPackageSettingsTEMP(); mSettings.removeUserLPw(userId); mPendingBroadcasts.remove(userId); mInstantAppRegistry.onUserRemovedLPw(userId); @@ -25131,7 +25110,7 @@ public class PackageManagerService extends IPackageManager.Stub if (async) { scheduleWriteSettingsLocked(); } else { - mSettings.writeLPr(); + writeSettingsLPrTEMP(); } } } @@ -25178,7 +25157,7 @@ public class PackageManagerService extends IPackageManager.Stub return; } mSettings.mReadExternalStorageEnforced = enforced ? Boolean.TRUE : Boolean.FALSE; - mSettings.writeLPr(); + writeSettingsLPrTEMP(); } } @@ -25692,6 +25671,17 @@ public class PackageManagerService extends IPackageManager.Stub public List<String> getMimeGroup(String packageName, String mimeGroup) { return mSettings.mPackages.get(packageName).getMimeGroup(mimeGroup); } + + /** + * Temporary method that wraps mSettings.writeLPr() and calls + * mPermissionManager.writePermissionsStateToPackageSettingsTEMP() beforehand. + * + * TODO(zhanghai): This should be removed once we finish migration of permission storage. + */ + private void writeSettingsLPrTEMP() { + mPermissionManager.writePermissionsStateToPackageSettingsTEMP(); + mSettings.writeLPr(); + } } interface PackageSender { @@ -25700,9 +25690,9 @@ interface PackageSender { * @param instantUserIds User IDs where the action occurred on an instant application */ void sendPackageBroadcast(final String action, final String pkg, - final Bundle extras, final int flags, final String targetPkg, - final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds, - @Nullable SparseArray<int[]> broadcastWhitelist); + final Bundle extras, final int flags, final String targetPkg, + final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds, + @Nullable SparseArray<int[]> broadcastAllowList); void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted, boolean includeStopped, int appId, int[] userIds, int[] instantUserIds, int dataLoaderType); diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index de0e4b53adab..491b4fc515ce 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -34,7 +34,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.ResolveInfo; @@ -68,7 +67,6 @@ import com.android.server.EventLogTags; import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.PackageDexUsage; import com.android.server.pm.parsing.pkg.AndroidPackage; -import com.android.server.pm.permission.PermissionsState; import dalvik.system.VMRuntime; @@ -968,20 +966,6 @@ public class PackageManagerServiceUtils { } /** - * Returns the {@link PermissionsState} for the given package. If the {@link PermissionsState} - * could not be found, {@code null} will be returned. - */ - public static PermissionsState getPermissionsState( - PackageManagerInternal packageManagerInternal, AndroidPackage pkg) { - final PackageSetting packageSetting = packageManagerInternal.getPackageSetting( - pkg.getPackageName()); - if (packageSetting == null) { - return null; - } - return packageSetting.getPermissionsState(); - } - - /** * Recursively create target directory */ public static void makeDirRecursive(File targetDir, int mode) throws ErrnoException { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 3e3e3c590491..8ceed139a5e5 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -954,93 +954,6 @@ public final class Settings { } } - /* - * Update the shared user setting when a package with a shared user id is removed. The gids - * associated with each permission of the deleted package are removed from the shared user' - * gid list only if its not in use by other permissions of packages in the shared user setting. - * - * @return the affected user id - */ - @UserIdInt - int updateSharedUserPermsLPw(PackageSetting deletedPs, int userId) { - if ((deletedPs == null) || (deletedPs.pkg == null)) { - Slog.i(PackageManagerService.TAG, - "Trying to update info for null package. Just ignoring"); - return UserHandle.USER_NULL; - } - - // No sharedUserId - if (deletedPs.sharedUser == null) { - return UserHandle.USER_NULL; - } - - SharedUserSetting sus = deletedPs.sharedUser; - - int affectedUserId = UserHandle.USER_NULL; - // Update permissions - for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) { - BasePermission bp = mPermissions.getPermission(eachPerm); - if (bp == null) { - continue; - } - - // Check if another package in the shared user needs the permission. - boolean used = false; - for (PackageSetting pkg : sus.packages) { - if (pkg.pkg != null - && !pkg.pkg.getPackageName().equals(deletedPs.pkg.getPackageName()) - && pkg.pkg.getRequestedPermissions().contains(eachPerm)) { - used = true; - break; - } - } - if (used) { - continue; - } - - PermissionsState permissionsState = sus.getPermissionsState(); - PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.getPackageName()); - - // If the package is shadowing is a disabled system package, - // do not drop permissions that the shadowed package requests. - if (disabledPs != null) { - boolean reqByDisabledSysPkg = false; - for (String permission : disabledPs.pkg.getRequestedPermissions()) { - if (permission.equals(eachPerm)) { - reqByDisabledSysPkg = true; - break; - } - } - if (reqByDisabledSysPkg) { - continue; - } - } - - // Try to revoke as an install permission which is for all users. - // The package is gone - no need to keep flags for applying policy. - permissionsState.updatePermissionFlags(bp, userId, - PackageManager.MASK_PERMISSION_FLAGS_ALL, 0); - - if (permissionsState.revokeInstallPermission(bp) == - PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) { - affectedUserId = UserHandle.USER_ALL; - } - - // Try to revoke as an install permission which is per user. - if (permissionsState.revokeRuntimePermission(bp, userId) == - PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) { - if (affectedUserId == UserHandle.USER_NULL) { - affectedUserId = userId; - } else if (affectedUserId != userId) { - // Multiple users affected. - affectedUserId = UserHandle.USER_ALL; - } - } - } - - return affectedUserId; - } - int removePackageLPw(String name) { final PackageSetting p = mPackages.get(name); if (p != null) { @@ -4647,6 +4560,9 @@ public final class Settings { pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.getCodePathString()); pw.print(prefix); pw.print(" legacyNativeLibraryDir="); pw.println(ps.legacyNativeLibraryPathString); + pw.print(prefix); pw.print(" extractNativeLibs="); + pw.println((ps.pkgFlags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0 + ? "true" : "false"); pw.print(prefix); pw.print(" primaryCpuAbi="); pw.println(ps.primaryCpuAbiString); pw.print(prefix); pw.print(" secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString); } @@ -5544,32 +5460,11 @@ public final class Settings { // Make sure we do not mHandler.removeMessages(userId); - for (SettingBase sb : mPackages.values()) { - revokeRuntimePermissionsAndClearFlags(sb, userId); - } - - for (SettingBase sb : mSharedUsers.values()) { - revokeRuntimePermissionsAndClearFlags(sb, userId); - } - mPermissionUpgradeNeeded.delete(userId); mVersions.delete(userId); mFingerprints.remove(userId); } - private void revokeRuntimePermissionsAndClearFlags(SettingBase sb, int userId) { - PermissionsState permissionsState = sb.getPermissionsState(); - for (PermissionState permissionState - : permissionsState.getRuntimePermissionStates(userId)) { - BasePermission bp = mPermissions.getPermission(permissionState.getName()); - if (bp != null) { - permissionsState.revokeRuntimePermission(bp, userId); - permissionsState.updatePermissionFlags(bp, userId, - PackageManager.MASK_PERMISSION_FLAGS_ALL, 0); - } - } - } - public void deleteUserRuntimePermissionsFile(int userId) { mPersistence.deleteForUser(UserHandle.of(userId)); } diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index f9bf54a11df0..ac05aabf998f 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -56,6 +56,7 @@ import android.os.UserManagerInternal; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.text.TextUtils; +import android.util.ArraySet; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; @@ -84,6 +85,7 @@ import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @@ -650,6 +652,7 @@ public class StagingManager { try { if (hasApex) { checkInstallationOfApkInApexSuccessful(session); + checkDuplicateApkInApex(session); snapshotAndRestoreForApexSession(session); Slog.i(TAG, "APEX packages in session " + session.sessionId + " were successfully activated. Proceeding with APK packages, if any"); @@ -829,6 +832,40 @@ public class StagingManager { return null; } + /** + * Throws a PackageManagerException if there are duplicate packages in apk and apk-in-apex. + */ + private void checkDuplicateApkInApex(@NonNull PackageInstallerSession session) + throws PackageManagerException { + if (!session.isMultiPackage()) { + return; + } + final int[] childSessionIds = session.getChildSessionIds(); + final Set<String> apkNames = new ArraySet<>(); + synchronized (mStagedSessions) { + for (int id : childSessionIds) { + final PackageInstallerSession s = mStagedSessions.get(id); + if (!isApexSession(s)) { + apkNames.add(s.getPackageName()); + } + } + } + final List<PackageInstallerSession> apexSessions = extractApexSessions(session); + for (PackageInstallerSession apexSession : apexSessions) { + String packageName = apexSession.getPackageName(); + for (String apkInApex : mApexManager.getApksInApex(packageName)) { + if (!apkNames.add(apkInApex)) { + throw new PackageManagerException( + SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, + "Package: " + packageName + " in session: " + + apexSession.sessionId + " has duplicate apk-in-apex: " + + apkInApex, null); + + } + } + } + } + private void installApksInSession(@NonNull PackageInstallerSession session) throws PackageManagerException { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index bf9506ad51f1..f66b4ee5a1a7 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -87,6 +87,7 @@ import android.stats.devicepolicy.DevicePolicyEnums; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; +import android.util.IndentingPrintWriter; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; @@ -103,7 +104,6 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.FrameworkStatsLog; -import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; @@ -141,6 +141,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; /** * Service for {@link UserManager}. @@ -443,6 +444,11 @@ public class UserManagerService extends IUserManager.Stub { } }; + // TODO(b/161915546): remove once userWithName() is fixed / removed + // Use to debug / dump when user 0 is allocated at userWithName() + public static final boolean DBG_ALLOCATION = false; // DO NOT SUBMIT WITH TRUE + public final AtomicInteger mUser0Allocations; + /** * Start an {@link IntentSender} when user is unlocked after disabling quiet mode. * @@ -629,6 +635,7 @@ public class UserManagerService extends IUserManager.Stub { LocalServices.addService(UserManagerInternal.class, mLocalService); mLockPatternUtils = new LockPatternUtils(mContext); mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING); + mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null; } void systemReady() { @@ -1310,6 +1317,10 @@ public class UserManagerService extends IUserManager.Stub { */ private UserInfo userWithName(UserInfo orig) { if (orig != null && orig.name == null && orig.id == UserHandle.USER_SYSTEM) { + if (DBG_ALLOCATION) { + final int number = mUser0Allocations.incrementAndGet(); + Slog.w(LOG_TAG, "System user instantiated at least " + number + " times"); + } UserInfo withName = new UserInfo(orig); withName.name = getOwnerName(); return withName; @@ -4786,6 +4797,7 @@ public class UserManagerService extends IUserManager.Stub { } } + pw.println(); pw.println("Device properties:"); pw.println(" Device owner id:" + mDeviceOwnerUserId); pw.println(); @@ -4814,12 +4826,9 @@ public class UserManagerService extends IUserManager.Stub { } pw.println(']'); } - synchronized (mUsersLock) { - pw.println(); - pw.print("Cached user IDs: "); + pw.print(" Cached user IDs: "); pw.println(Arrays.toString(mUserIds)); - pw.println(); } } // synchronized (mPackagesLock) @@ -4835,6 +4844,10 @@ public class UserManagerService extends IUserManager.Stub { pw.println(" Is split-system user: " + UserManager.isSplitSystemUser()); pw.println(" Is headless-system mode: " + UserManager.isHeadlessSystemUserMode()); pw.println(" User version: " + mUserVersion); + pw.println(" Owner name: " + getOwnerName()); + if (DBG_ALLOCATION) { + pw.println(" System user allocations: " + mUser0Allocations.get()); + } // Dump UserTypes pw.println(); @@ -4844,9 +4857,17 @@ public class UserManagerService extends IUserManager.Stub { mUserTypes.valueAt(i).dump(pw, " "); } - // Dump package whitelist - pw.println(); - mSystemPackageInstaller.dump(pw); + // TODO: create IndentingPrintWriter at the beginning of dump() and use the proper + // indentation methods instead of explicit printing " " + try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw)) { + + // Dump SystemPackageInstaller info + ipw.println(); + mSystemPackageInstaller.dump(ipw); + + // NOTE: pw's not available after this point as it's auto-closed by ipw, so new dump + // statements should use ipw below + } } private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) { diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 3c1d189dc102..f7e9e34a4702 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -139,6 +139,11 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_CONFIG_PRIVATE_DNS }); + public static final Set<String> DEPRECATED_USER_RESTRICTIONS = Sets.newArraySet( + UserManager.DISALLOW_ADD_MANAGED_PROFILE, + UserManager.DISALLOW_REMOVE_MANAGED_PROFILE + ); + /** * Set of user restriction which we don't want to persist. */ diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java index 492b84a0a84b..b95404febf72 100644 --- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java +++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java @@ -28,15 +28,14 @@ import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; +import android.util.IndentingPrintWriter; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.SystemConfig; import com.android.server.pm.parsing.pkg.AndroidPackage; -import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -723,13 +722,7 @@ class UserSystemPackageInstaller { return userTypeList; } - void dump(PrintWriter pw) { - try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) { - dumpIndented(ipw); - } - } - - private void dumpIndented(IndentingPrintWriter pw) { + void dump(IndentingPrintWriter pw) { final int mode = getWhitelistMode(); pw.println("Whitelisted packages per user type"); diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java index cfa0449aaf33..962638b4f63c 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/BasePermission.java @@ -38,7 +38,6 @@ import android.util.Slog; import com.android.server.pm.DumpState; import com.android.server.pm.PackageManagerService; -import com.android.server.pm.PackageSetting; import com.android.server.pm.PackageSettingBase; import com.android.server.pm.parsing.PackageInfoUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; @@ -420,8 +419,7 @@ public final class BasePermission { } public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg, - PackageSetting pkgSetting) { - final PermissionsState permsState = pkgSetting.getPermissionsState(); + PermissionsState permsState) { int index = pkg.getRequestedPermissions().indexOf(name); if (!permsState.hasRequestedPermission(name) && index == -1) { throw new SecurityException("Package " + pkg.getPackageName() diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 03771be0ce7c..86d767dd5df4 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -83,6 +83,7 @@ import android.content.pm.PackageParser; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; +import android.content.pm.UserInfo; import android.content.pm.parsing.component.ParsedPermission; import android.content.pm.parsing.component.ParsedPermissionGroup; import android.content.pm.permission.SplitPermissionInfoParcelable; @@ -120,6 +121,7 @@ import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; +import android.util.TimingsTraceLog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -140,7 +142,6 @@ import com.android.server.Watchdog; import com.android.server.pm.ApexManager; import com.android.server.pm.PackageManagerServiceUtils; import com.android.server.pm.PackageSetting; -import com.android.server.pm.SharedUserSetting; import com.android.server.pm.UserManagerService; import com.android.server.pm.parsing.PackageInfoUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; @@ -225,6 +226,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { /** Internal connection to the user manager */ private final UserManagerInternal mUserManagerInt; + /** Maps from App ID to PermissionsState */ + private final SparseArray<PermissionsState> mAppIdStates = new SparseArray<>(); + /** Permission controller: User space permission management */ private PermissionControllerManager mPermissionControllerManager; @@ -669,11 +673,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (pkg == null) { return 0; } - final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( - pkg.getPackageName()); - if (ps == null) { - return 0; - } synchronized (mLock) { if (mSettings.getPermissionLocked(permName) == null) { return 0; @@ -682,7 +681,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) { return 0; } - PermissionsState permissionsState = ps.getPermissionsState(); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + packageName); + return 0; + } return permissionsState.getPermissionFlags(permName, userId); } @@ -769,9 +772,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); - final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( - packageName); - if (pkg == null || ps == null) { + if (pkg == null) { Log.e(TAG, "Unknown package: " + packageName); return; } @@ -787,7 +788,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown permission: " + permName); } - final PermissionsState permissionsState = ps.getPermissionsState(); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + packageName); + return; + } + final boolean hadState = permissionsState.getRuntimePermissionState(permName, userId) != null; if (!hadState) { @@ -862,12 +868,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { final boolean[] changed = new boolean[1]; mPackageManagerInt.forEachPackage(pkg -> { - final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( - pkg.getPackageName()); - if (ps == null) { + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return; } - final PermissionsState permissionsState = ps.getPermissionsState(); changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions( userId, effectiveFlagMask, effectiveFlagValues); mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid()); @@ -879,7 +884,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Override - public int checkPermission(String permName, String pkgName, int userId) { + public int checkPermission(String permName, String pkgName, @UserIdInt int userId) { // Not using Objects.requireNonNull() here for compatibility reasons. if (permName == null || pkgName == null) { return PackageManager.PERMISSION_DENIED; @@ -921,12 +926,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { } final int uid = UserHandle.getUid(userId, pkg.getUid()); - final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( - pkg.getPackageName()); - if (ps == null) { + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return PackageManager.PERMISSION_DENIED; } - final PermissionsState permissionsState = ps.getPermissionsState(); if (checkSinglePermissionInternal(uid, permissionsState, permissionName)) { return PackageManager.PERMISSION_GRANTED; @@ -1137,9 +1141,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { final long identity = Binder.clearCallingIdentity(); try { - final PermissionsState permissionsState = - PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg); + final PermissionsState permissionsState = getPermissionsState(pkg); if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + packageName); return null; } @@ -1449,7 +1453,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown package: " + packageName); } - bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); + return; + } + + bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState); // If a permission review is required for legacy apps we represent // their permissions as always granted runtime ones since we need @@ -1462,8 +1472,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid())); - final PermissionsState permissionsState = ps.getPermissionsState(); - final int flags = permissionsState.getPermissionFlags(permName, userId); if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) { Log.e(TAG, "Cannot grant system fixed permission " @@ -1597,9 +1605,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { "revokeRuntimePermission"); final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); - final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( - packageName); - if (pkg == null || ps == null) { + if (pkg == null) { Log.e(TAG, "Unknown package: " + packageName); return; } @@ -1611,7 +1617,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown permission: " + permName); } - bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps); + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); + return; + } + + bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState); // If a permission review is required for legacy apps we represent // their permissions as always granted runtime ones since we need @@ -1622,8 +1634,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { return; } - final PermissionsState permissionsState = ps.getPermissionsState(); - final int flags = permissionsState.getPermissionFlags(permName, userId); // Only the system may revoke SYSTEM_FIXED permissions. if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0 @@ -2454,14 +2464,36 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } + private void onUserRemoved(@UserIdInt int userId) { + synchronized (mLock) { + final int appIdStatesSize = mAppIdStates.size(); + for (int i = 0; i < appIdStatesSize; i++) { + PermissionsState permissionsState = mAppIdStates.valueAt(i); + for (PermissionState permissionState + : permissionsState.getRuntimePermissionStates(userId)) { + BasePermission bp = mSettings.getPermission(permissionState.getName()); + if (bp != null) { + permissionsState.revokeRuntimePermission(bp, userId); + permissionsState.updatePermissionFlags(bp, userId, + PackageManager.MASK_PERMISSION_FLAGS_ALL, 0); + } + } + } + } + } + @NonNull private Set<String> getGrantedPermissions(@NonNull String packageName, @UserIdInt int userId) { - final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName); - if (ps == null) { + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); + if (pkg == null) { + return null; + } + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return null; } - final PermissionsState permissionsState = ps.getPermissionsState(); return permissionsState.getPermissions(userId); } @@ -2476,11 +2508,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { @Nullable private int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId) { - final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName); - if (ps == null) { + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); + if (pkg == null) { + return null; + } + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return null; } - final PermissionsState permissionsState = ps.getPermissionsState(); return permissionsState.computeGids(userId); } @@ -2518,15 +2554,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (ps == null) { return; } + final PermissionsState permissionsState = getOrCreatePermissionsState(pkg); - final PermissionsState permissionsState = ps.getPermissionsState(); - - final int[] currentUserIds = UserManagerService.getInstance().getUserIds(); + final int[] userIds = getAllUserIds(); boolean runtimePermissionsRevoked = false; int[] updatedUserIds = EMPTY_INT_ARRAY; - for (int userId : currentUserIds) { + for (int userId : userIds) { if (permissionsState.isMissing(userId)) { Collection<String> requestedPermissions; int targetSdkVersion; @@ -2591,8 +2626,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { // changed runtime permissions here are promotion of an install to // runtime and revocation of a runtime from a shared user. synchronized (mLock) { - updatedUserIds = revokeUnusedSharedUserPermissionsLocked(ps.getSharedUser(), - currentUserIds); + updatedUserIds = revokeUnusedSharedUserPermissionsLocked( + ps.getSharedUser().getPackages(), permissionsState, userIds); if (!ArrayUtils.isEmpty(updatedUserIds)) { runtimePermissionsRevoked = true; } @@ -2747,7 +2782,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // a runtime permission being downgraded to an install one. // Also in permission review mode we keep dangerous permissions // for legacy apps - for (int userId : currentUserIds) { + for (int userId : userIds) { if (origPermissions.getRuntimePermissionState( perm, userId) != null) { // Revoke the runtime permission and clear the flags. @@ -2770,7 +2805,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { boolean hardRestricted = bp.isHardRestricted(); boolean softRestricted = bp.isSoftRestricted(); - for (int userId : currentUserIds) { + for (int userId : userIds) { // If permission policy is not ready we don't deal with restricted // permissions as the policy may whitelist some permissions. Once // the policy is initialized we would re-evaluate permissions. @@ -2909,7 +2944,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { boolean hardRestricted = bp.isHardRestricted(); boolean softRestricted = bp.isSoftRestricted(); - for (int userId : currentUserIds) { + for (int userId : userIds) { // If permission policy is not ready we don't deal with restricted // permissions as the policy may whitelist some permissions. Once // the policy is initialized we would re-evaluate permissions. @@ -3061,13 +3096,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { synchronized (mLock) { updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg, - currentUserIds, updatedUserIds); + userIds, updatedUserIds); updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions, - permissionsState, pkg, newImplicitPermissions, currentUserIds, updatedUserIds); - updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, currentUserIds, + permissionsState, pkg, newImplicitPermissions, userIds, updatedUserIds); + updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, userIds, updatedUserIds); } + // TODO: Kill UIDs whose GIDs or runtime permissions changed. This might be more important + // for shared users. // Persist the runtime permissions state for users with changes. If permissions // were revoked because no app in the shared user declares them we have to // write synchronously to avoid losing runtime permissions state. @@ -3081,6 +3118,25 @@ public class PermissionManagerService extends IPermissionManager.Stub { } /** + * Returns all relevant user ids. This list include the current set of created user ids as well + * as pre-created user ids. + * @return user ids for created users and pre-created users + */ + private int[] getAllUserIds() { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("getAllUserIds"); + List<UserInfo> users = UserManagerService.getInstance().getUsers( + /*excludePartial=*/ true, /*excludeDying=*/ true, /*excludePreCreated=*/ false); + int size = users.size(); + final int[] userIds = new int[size]; + for (int i = 0; i < size; i++) { + userIds[i] = users.get(i).id; + } + t.traceEnd(); + return userIds; + } + + /** * Revoke permissions that are not implicit anymore and that have * {@link PackageManager#FLAG_PERMISSION_REVOKE_WHEN_REQUESTED} set. * @@ -3512,37 +3568,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { final PackageSetting disabledPs = mPackageManagerInt .getDisabledSystemPackage(pkg.getPackageName()); final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg; - if (disabledPs != null - && disabledPs.getPermissionsState().hasInstallPermission(perm)) { - // If the original was granted this permission, we take - // that grant decision as read and propagate it to the - // update. - if ((privilegedPermission && disabledPs.isPrivileged()) - || (oemPermission && disabledPs.isOem() - && canGrantOemPermission(disabledPs, perm))) { - allowed = true; - } - } else { - // The system apk may have been updated with an older - // version of the one on the data partition, but which - // granted a new system permission that it didn't have - // before. In this case we do want to allow the app to - // now get the new permission if the ancestral apk is - // privileged to get it. - if (disabledPs != null && disabledPkg != null - && isPackageRequestingPermission(disabledPkg, perm) - && ((privilegedPermission && disabledPs.isPrivileged()) - || (oemPermission && disabledPs.isOem() - && canGrantOemPermission(disabledPs, perm)))) { - allowed = true; - } + if (disabledPkg != null && isPackageRequestingPermission(disabledPkg, perm) + && ((privilegedPermission && disabledPkg.isPrivileged()) + || (oemPermission && canGrantOemPermission(disabledPkg, + perm)))) { + allowed = true; } } else { - final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( - pkg.getPackageName()); allowed = (privilegedPermission && pkg.isPrivileged()) - || (oemPermission && pkg.isOem() - && canGrantOemPermission(ps, perm)); + || (oemPermission && canGrantOemPermission(pkg, perm)); } // In any case, don't grant a privileged permission to privileged vendor apps, if // the permission's protectionLevel does not have the extra 'vendorPrivileged' @@ -3693,16 +3727,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { return false; } - private static boolean canGrantOemPermission(PackageSetting ps, String permission) { - if (!ps.isOem()) { + private static boolean canGrantOemPermission(AndroidPackage pkg, String permission) { + if (!pkg.isOem()) { return false; } // all oem permissions must explicitly be granted or denied final Boolean granted = - SystemConfig.getInstance().getOemPermissions(ps.name).get(permission); + SystemConfig.getInstance().getOemPermissions(pkg.getPackageName()).get(permission); if (granted == null) { throw new IllegalStateException("OEM permission" + permission + " requested by package " - + ps.name + " must be explicitly declared granted or not"); + + pkg.getPackageName() + " must be explicitly declared granted or not"); } return Boolean.TRUE == granted; } @@ -3715,12 +3749,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { } // Legacy apps have the permission and get user consent on launch. - final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( - pkg.getPackageName()); - if (ps == null) { + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return false; } - final PermissionsState permissionsState = ps.getPermissionsState(); return permissionsState.isPermissionReviewRequired(userId); } @@ -3745,14 +3778,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { private void grantRequestedRuntimePermissionsForUser(AndroidPackage pkg, int userId, String[] grantedPermissions, int callingUid, PermissionCallback callback) { - PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( - pkg.getPackageName()); - if (ps == null) { + final PermissionsState permissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return; } - PermissionsState permissionsState = ps.getPermissionsState(); - final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED | PackageManager.FLAG_PERMISSION_POLICY_FIXED; @@ -3796,9 +3827,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { private void setWhitelistedRestrictedPermissionsForUsers(@NonNull AndroidPackage pkg, @UserIdInt int[] userIds, @Nullable List<String> permissions, int callingUid, @PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) { - final PermissionsState permissionsState = - PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg); + final PermissionsState permissionsState = getPermissionsState(pkg); if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); return; } @@ -3916,9 +3947,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int j = 0; j < oldGrantedCount; j++) { final String permission = oldPermsForUser.valueAt(j); // Sometimes we create a new permission state instance during update. - final PermissionsState newPermissionsState = - PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, - pkg); + final PermissionsState newPermissionsState = getPermissionsState(pkg); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()); + continue; + } if (!newPermissionsState.hasPermission(permission, userId)) { callback.onPermissionRevoked(pkg.getUid(), userId, null); break; @@ -3930,10 +3963,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { @GuardedBy("mLock") private int[] revokeUnusedSharedUserPermissionsLocked( - SharedUserSetting suSetting, int[] allUserIds) { + List<AndroidPackage> pkgList, PermissionsState permissionsState, int[] allUserIds) { // Collect all used permissions in the UID final ArraySet<String> usedPermissions = new ArraySet<>(); - final List<AndroidPackage> pkgList = suSetting.getPackages(); if (pkgList == null || pkgList.size() == 0) { return EmptyArray.INT; } @@ -3951,7 +3983,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - PermissionsState permissionsState = suSetting.getPermissionsState(); // Prune install permissions List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates(); final int installPermCount = installPermStates.size(); @@ -4237,12 +4268,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } else { mPackageManagerInt.forEachPackage(p -> { - PackageSetting ps = mPackageManagerInt.getPackageSetting( - p.getPackageName()); - if (ps == null) { + final PermissionsState permissionsState = getPermissionsState(p); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + p.getPackageName()); return; } - PermissionsState permissionsState = ps.getPermissionsState(); if (permissionsState.getInstallPermissionState(bp.getName()) != null) { permissionsState.revokeInstallPermission(bp); permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, @@ -4649,6 +4679,66 @@ public class PermissionManagerService extends IPermissionManager.Stub { return mBackgroundPermissions; } + @Nullable + private PermissionsState getPermissionsState(@NonNull AndroidPackage pkg) { + return getPermissionsState(pkg.getUid()); + } + + @Nullable + private PermissionsState getPermissionsState(int appId) { + synchronized (mLock) { + return mAppIdStates.get(appId); + } + } + + @Nullable + private PermissionsState getOrCreatePermissionsState(@NonNull AndroidPackage pkg) { + return getOrCreatePermissionsState(pkg.getUid()); + } + + @Nullable + private PermissionsState getOrCreatePermissionsState(int appId) { + synchronized (mLock) { + PermissionsState state = mAppIdStates.get(appId); + if (state == null) { + state = new PermissionsState(); + mAppIdStates.put(appId, state); + } + return state; + } + } + + private void removePermissionsState(int appId) { + synchronized (mLock) { + mAppIdStates.remove(appId); + } + } + + private void readPermissionsStateFromPackageSettings() { + mPackageManagerInt.forEachPackageSetting(ps -> { + synchronized (mLock) { + final int appId = ps.pkg.getUid(); + if (!mAppIdStates.contains(appId)) { + mAppIdStates.put(appId, new PermissionsState(ps.getPermissionsState())); + } + } + }); + } + + private void writePermissionsStateToPackageSettings() { + mPackageManagerInt.forEachPackageSetting(ps -> { + synchronized (mLock) { + final int appId = ps.pkg.getUid(); + final PermissionsState permissionsState = mAppIdStates.get(appId); + if (permissionsState == null) { + Slog.e(TAG, "Missing permissions state for " + ps.pkg.getPackageName()); + return; + } + ps.getPermissionsState().copyFrom(permissionsState); + } + }); + } + private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal { @Override public void systemReady() { @@ -4680,6 +4770,22 @@ public class PermissionManagerService extends IPermissionManager.Stub { public void removeAllPermissions(AndroidPackage pkg, boolean chatty) { PermissionManagerService.this.removeAllPermissions(pkg, chatty); } + @Override + public void readPermissionsStateFromPackageSettingsTEMP() { + PermissionManagerService.this.readPermissionsStateFromPackageSettings(); + } + @Override + public void writePermissionsStateToPackageSettingsTEMP() { + PermissionManagerService.this.writePermissionsStateToPackageSettings(); + } + @Override + public void onUserRemoved(@UserIdInt int userId) { + PermissionManagerService.this.onUserRemoved(userId); + } + @Override + public void removePermissionsStateTEMP(int appId) { + PermissionManagerService.this.removePermissionsState(appId); + } @NonNull @Override public Set<String> getGrantedPermissions(@NonNull String packageName, diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index cfa371ddbad3..5c7ff1f9a1ad 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -265,6 +265,37 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); /** + * Read {@code PermissionsState} from package settings. + * + * TODO(zhanghai): This is a temporary method because we should not expose + * {@code PackageSetting} which is a implementation detail that permission should not know. + * Instead, it should retrieve the legacy state via a defined API. + */ + public abstract void readPermissionsStateFromPackageSettingsTEMP(); + + /** + * Write {@code PermissionsState} from to settings. + * + * TODO(zhanghai): This is a temporary method and should be removed once we migrated persistence + * for permission. + */ + public abstract void writePermissionsStateToPackageSettingsTEMP(); + + /** + * Notify that a user has been removed and its permission state should be removed as well. + */ + public abstract void onUserRemoved(@UserIdInt int userId); + + /** + * Remove the {@code PermissionsState} associated with an app ID, called the same time as the + * removal of a {@code PackageSetitng}. + * + * TODO(zhanghai): This is a temporary method before we figure out a way to get notified of app + * ID removal via API. + */ + public abstract void removePermissionsStateTEMP(int appId); + + /** * Get all the permissions granted to a package. */ @NonNull diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 4d48a2e63b30..ae2b040d0a89 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -89,7 +89,7 @@ import java.util.concurrent.ExecutionException; public final class PermissionPolicyService extends SystemService { private static final String LOG_TAG = PermissionPolicyService.class.getSimpleName(); private static final boolean DEBUG = false; - private static final long USER_SENSITIVE_UPDATE_DELAY_MS = 10000; + private static final long USER_SENSITIVE_UPDATE_DELAY_MS = 60000; private final Object mLock = new Object(); @@ -283,6 +283,11 @@ public final class PermissionPolicyService extends SystemService { manager.updateUserSensitiveForApp(uid); } }, UserHandle.ALL, intentFilter, null, null); + + PermissionControllerManager manager = new PermissionControllerManager( + getUserContext(getContext(), Process.myUserHandle()), FgThread.getHandler()); + FgThread.getHandler().postDelayed(manager::updateUserSensitive, + USER_SENSITIVE_UPDATE_DELAY_MS); } /** @@ -425,8 +430,7 @@ public final class PermissionPolicyService extends SystemService { throw new IllegalStateException(e); } - FgThread.getHandler().postDelayed(permissionControllerManager::updateUserSensitive, - USER_SENSITIVE_UPDATE_DELAY_MS); + permissionControllerManager.updateUserSensitive(); packageManagerInternal.updateRuntimePermissionsFingerprint(userId); } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index fa3bcb6b98eb..548cd70de4d1 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -450,7 +450,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { volatile int mPendingWakeKey = PENDING_KEY_NULL; int mRecentAppsHeldModifiers; - boolean mLanguageSwitchKeyPressed; int mCameraLensCoverState = CAMERA_LENS_COVER_ABSENT; boolean mHaveBuiltInKeyboard; @@ -2938,12 +2937,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction); return -1; } - if (mLanguageSwitchKeyPressed && !down - && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH - || keyCode == KeyEvent.KEYCODE_SPACE)) { - mLanguageSwitchKeyPressed = false; - return -1; - } if (isValidGlobalKey(keyCode) && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java index ef4954aa4e4c..ae0db4419080 100644 --- a/services/core/java/com/android/server/power/ThermalManagerService.java +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -200,7 +200,7 @@ public class ThermalManagerService extends SystemService { final int count = mTemperatureMap.size(); for (int i = 0; i < count; i++) { Temperature t = mTemperatureMap.valueAt(i); - if (t.getStatus() >= newStatus) { + if (t.getType() == Temperature.TYPE_SKIN && t.getStatus() >= newStatus) { newStatus = t.getStatus(); } } diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java index 2a74b3d23829..5aedfc19028b 100644 --- a/services/core/java/com/android/server/slice/SliceManagerService.java +++ b/services/core/java/com/android/server/slice/SliceManagerService.java @@ -28,8 +28,6 @@ import static android.os.Process.SYSTEM_UID; import android.Manifest.permission; import android.annotation.NonNull; import android.app.AppOpsManager; -import android.app.role.OnRoleHoldersChangedListener; -import android.app.role.RoleManager; import android.app.slice.ISliceManager; import android.app.slice.SliceSpec; import android.app.usage.UsageStatsManagerInternal; @@ -41,9 +39,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; import android.content.pm.ProviderInfo; -import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Binder; import android.os.Handler; @@ -65,7 +61,6 @@ import com.android.internal.app.AssistUtils; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemService; -import com.android.server.SystemService.TargetUser; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -77,10 +72,7 @@ import java.io.ByteArrayOutputStream; import java.io.FileDescriptor; import java.io.IOException; import java.util.ArrayList; -import java.util.List; import java.util.Objects; -import java.util.concurrent.Executor; -import java.util.function.Supplier; public class SliceManagerService extends ISliceManager.Stub { @@ -88,16 +80,13 @@ public class SliceManagerService extends ISliceManager.Stub { private final Object mLock = new Object(); private final Context mContext; - private final PackageManagerInternal mPackageManagerInternal; private final AppOpsManager mAppOps; private final AssistUtils mAssistUtils; @GuardedBy("mLock") private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>(); @GuardedBy("mLock") - private final SparseArray<PackageMatchingCache> mAssistantLookup = new SparseArray<>(); - @GuardedBy("mLock") - private final SparseArray<PackageMatchingCache> mHomeLookup = new SparseArray<>(); + private final SparseArray<String> mLastAssistantPackage = new SparseArray<>(); private final Handler mHandler; private final SlicePermissionManager mPermissions; @@ -110,8 +99,6 @@ public class SliceManagerService extends ISliceManager.Stub { @VisibleForTesting SliceManagerService(Context context, Looper looper) { mContext = context; - mPackageManagerInternal = Objects.requireNonNull( - LocalServices.getService(PackageManagerInternal.class)); mAppOps = context.getSystemService(AppOpsManager.class); mAssistUtils = new AssistUtils(context); mHandler = new Handler(looper); @@ -124,7 +111,6 @@ public class SliceManagerService extends ISliceManager.Stub { filter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); - mRoleObserver = new RoleObserver(); mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); } @@ -174,8 +160,7 @@ public class SliceManagerService extends ISliceManager.Stub { mHandler.post(() -> { if (slicePkg != null && !Objects.equals(pkg, slicePkg)) { mAppUsageStats.reportEvent(slicePkg, user, - isAssistant(pkg, user) || isDefaultHomeApp(pkg, user) - ? SLICE_PINNED_PRIV : SLICE_PINNED); + isAssistant(pkg, user) ? SLICE_PINNED_PRIV : SLICE_PINNED); } }); } @@ -440,38 +425,19 @@ public class SliceManagerService extends ISliceManager.Stub { private boolean hasFullSliceAccess(String pkg, int userId) { long ident = Binder.clearCallingIdentity(); try { - boolean ret = isDefaultHomeApp(pkg, userId) || isAssistant(pkg, userId) - || isGrantedFullAccess(pkg, userId); - return ret; + return isAssistant(pkg, userId) || isGrantedFullAccess(pkg, userId); } finally { Binder.restoreCallingIdentity(ident); } } private boolean isAssistant(String pkg, int userId) { - return getAssistantMatcher(userId).matches(pkg); - } - - private boolean isDefaultHomeApp(String pkg, int userId) { - return getHomeMatcher(userId).matches(pkg); - } - - private PackageMatchingCache getAssistantMatcher(int userId) { - PackageMatchingCache matcher = mAssistantLookup.get(userId); - if (matcher == null) { - matcher = new PackageMatchingCache(() -> getAssistant(userId)); - mAssistantLookup.put(userId, matcher); - } - return matcher; - } - - private PackageMatchingCache getHomeMatcher(int userId) { - PackageMatchingCache matcher = mHomeLookup.get(userId); - if (matcher == null) { - matcher = new PackageMatchingCache(() -> getDefaultHome(userId)); - mHomeLookup.put(userId, matcher); + if (pkg == null) return false; + if (!pkg.equals(mLastAssistantPackage.get(userId))) { + // Failed on cached value, try updating. + mLastAssistantPackage.put(userId, getAssistant(userId)); } - return matcher; + return pkg.equals(mLastAssistantPackage.get(userId)); } private String getAssistant(int userId) { @@ -482,111 +448,6 @@ public class SliceManagerService extends ISliceManager.Stub { return cn.getPackageName(); } - /** - * A cached value of the default home app - */ - private String mCachedDefaultHome = null; - - // Based on getDefaultHome in ShortcutService. - // TODO: Unify if possible - @VisibleForTesting - protected String getDefaultHome(int userId) { - - // Set VERIFY to true to run the cache in "shadow" mode for cache - // testing. Do not commit set to true; - final boolean VERIFY = false; - - if (mCachedDefaultHome != null) { - if (!VERIFY) { - return mCachedDefaultHome; - } - } - - final long token = Binder.clearCallingIdentity(); - try { - final List<ResolveInfo> allHomeCandidates = new ArrayList<>(); - - // Default launcher from package manager. - final ComponentName defaultLauncher = mPackageManagerInternal - .getHomeActivitiesAsUser(allHomeCandidates, userId); - - ComponentName detected = defaultLauncher; - - // Cache the default launcher. It is not a problem if the - // launcher is null - eventually, the default launcher will be - // set to something non-null. - mCachedDefaultHome = ((detected != null) ? detected.getPackageName() : null); - - if (detected == null) { - // If we reach here, that means it's the first check since the user was created, - // and there's already multiple launchers and there's no default set. - // Find the system one with the highest priority. - // (We need to check the priority too because of FallbackHome in Settings.) - // If there's no system launcher yet, then no one can access slices, until - // the user explicitly sets one. - final int size = allHomeCandidates.size(); - - int lastPriority = Integer.MIN_VALUE; - for (int i = 0; i < size; i++) { - final ResolveInfo ri = allHomeCandidates.get(i); - if (!ri.activityInfo.applicationInfo.isSystemApp()) { - continue; - } - if (ri.priority < lastPriority) { - continue; - } - detected = ri.activityInfo.getComponentName(); - lastPriority = ri.priority; - } - } - final String ret = ((detected != null) ? detected.getPackageName() : null); - if (VERIFY) { - if (mCachedDefaultHome != null && !mCachedDefaultHome.equals(ret)) { - Slog.e(TAG, "getDefaultHome() cache failure, is " + - mCachedDefaultHome + " should be " + ret); - } - } - return ret; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public void invalidateCachedDefaultHome() { - mCachedDefaultHome = null; - } - - /** - * Listen for changes in the roles, and invalidate the cached default - * home as necessary. - */ - private RoleObserver mRoleObserver; - - class RoleObserver implements OnRoleHoldersChangedListener { - private RoleManager mRm; - private final Executor mExecutor; - - RoleObserver() { - mExecutor = mContext.getMainExecutor(); - register(); - } - - public void register() { - mRm = mContext.getSystemService(RoleManager.class); - if (mRm != null) { - mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL); - invalidateCachedDefaultHome(); - } - } - - @Override - public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) { - if (RoleManager.ROLE_HOME.equals(roleName)) { - invalidateCachedDefaultHome(); - } - } - } - private boolean isGrantedFullAccess(String pkg, int userId) { return mPermissions.hasFullAccess(pkg, userId); } @@ -635,30 +496,6 @@ public class SliceManagerService extends ISliceManager.Stub { return mPermissions.getAllPackagesGranted(pkg); } - /** - * Holder that caches a package that has access to a slice. - */ - static class PackageMatchingCache { - - private final Supplier<String> mPkgSource; - private String mCurrentPkg; - - public PackageMatchingCache(Supplier<String> pkgSource) { - mPkgSource = pkgSource; - } - - public boolean matches(String pkgCandidate) { - if (pkgCandidate == null) return false; - - if (Objects.equals(pkgCandidate, mCurrentPkg)) { - return true; - } - // Failed on cached value, try updating. - mCurrentPkg = mPkgSource.get(); - return Objects.equals(pkgCandidate, mCurrentPkg); - } - } - public static class Lifecycle extends SystemService { private SliceManagerService mService; diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java index c2b0d1067e38..0ca36e0fc258 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java @@ -72,6 +72,10 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat builder.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED); } + // TODO(b/149014708) Replace this with real logic when the settings storage is fully + // implemented. + builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED); + // The ability to make manual time zone suggestions can also be restricted by policy. With // the current logic above, this could lead to a situation where a device hardware does not // support auto detection, the device has been forced into "auto" mode by an admin and the @@ -90,6 +94,7 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) { return new TimeZoneConfiguration.Builder() .setAutoDetectionEnabled(isAutoDetectionEnabled()) + .setGeoDetectionEnabled(isGeoDetectionEnabled()) .build(); } @@ -105,8 +110,11 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat // detection: if we wrote it down then we'd set the default explicitly. That might influence // what happens on later releases that do support auto detection on the same hardware. if (isAutoDetectionSupported()) { - final int value = configuration.isAutoDetectionEnabled() ? 1 : 0; - Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, value); + final int autoEnabledValue = configuration.isAutoDetectionEnabled() ? 1 : 0; + Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, autoEnabledValue); + + final boolean geoTzDetectionEnabledValue = configuration.isGeoDetectionEnabled(); + // TODO(b/149014708) Write this down to user-scoped settings once implemented. } } @@ -126,6 +134,14 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat } @Override + public boolean isGeoDetectionEnabled() { + // TODO(b/149014708) Read this from user-scoped settings once implemented. The user's + // location toggle will act as an override for this setting, i.e. so that the setting will + // return false if the location toggle is disabled. + return false; + } + + @Override public boolean isDeviceTimeZoneInitialized() { // timezone.equals("GMT") will be true and only true if the time zone was // set to a default value by the system server (when starting, system server diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java index 3d9ec6475a8b..fb7a73d12632 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; * The internal (in-process) system server API for the {@link * com.android.server.timezonedetector.TimeZoneDetectorService}. * + * <p>The methods on this class can be called from any thread. * @hide */ public interface TimeZoneDetectorInternal extends Dumpable.Container { @@ -29,7 +30,7 @@ public interface TimeZoneDetectorInternal extends Dumpable.Container { /** * Suggests the current time zone, determined using geolocation, to the detector. The * detector may ignore the signal based on system settings, whether better information is - * available, and so on. + * available, and so on. This method may be implemented asynchronously. */ void suggestGeolocationTimeZone(@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion); } diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java index 4464f7d136e3..15412a0d14a1 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java @@ -58,6 +58,7 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter @NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) { Objects.requireNonNull(timeZoneSuggestion); + // All strategy calls must take place on the mHandler thread. mHandler.post( () -> mTimeZoneDetectorStrategy.suggestGeolocationTimeZone(timeZoneSuggestion)); } diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java index 7467439905eb..d81f949742bd 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java @@ -130,6 +130,10 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub service.handleAutoTimeZoneConfigChanged(); } }); + // TODO(b/149014708) Listen for changes to geolocation time zone detection enabled config. + // This should also include listening to the current user and the current user's location + // toggle since the config is user-scoped and the location toggle overrides the geolocation + // time zone enabled setting. return service; } @@ -280,7 +284,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub void handleConfigurationChanged() { // Note: we could trigger an async time zone detection operation here via a call to - // handleAutoTimeZoneDetectionChanged(), but that is triggered in response to the underlying + // handleAutoTimeZoneConfigChanged(), but that is triggered in response to the underlying // setting value changing so it is currently unnecessary. If we get to a point where all // configuration changes are guaranteed to happen in response to an updateConfiguration() // call, then we can remove that path and call it here instead. @@ -288,7 +292,6 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub // Configuration has changed, but each user may have a different view of the configuration. // It's possible that this will cause unnecessary notifications but that shouldn't be a // problem. - synchronized (mConfigurationListeners) { final int userCount = mConfigurationListeners.size(); for (int userIndex = 0; userIndex < userCount; userIndex++) { diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java index f947a6554412..c5b7e39f4fef 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java @@ -30,9 +30,9 @@ import android.util.IndentingPrintWriter; * <p>The strategy uses suggestions to decide whether to modify the device's time zone setting * and what to set it to. * - * <p>Most calls will be handled by a single thread but that is not true for all calls. For example - * {@link #dump(IndentingPrintWriter, String[])}) may be called on a different thread so - * implementations mustvhandle thread safety. + * <p>Most calls will be handled by a single thread, but that is not true for all calls. For example + * {@link #dump(IndentingPrintWriter, String[])}) may be called on a different thread concurrently + * with other operations so implementations must still handle thread safety. * * @hide */ diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java index 9c36c3921e3e..d1369a289428 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java @@ -23,6 +23,7 @@ import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_S import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE; import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED; import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_AUTO_DETECTION_ENABLED; +import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_GEO_DETECTION_ENABLED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -98,6 +99,12 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat boolean isAutoDetectionEnabled(); /** + * Returns whether geolocation can be used for time zone detection when {@link + * #isAutoDetectionEnabled()} returns {@code true}. + */ + boolean isGeoDetectionEnabled(); + + /** * Returns true if the device has had an explicit time zone set. */ boolean isDeviceTimeZoneInitialized(); @@ -200,7 +207,15 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat */ @GuardedBy("this") private ArrayMapWithHistory<Integer, QualifiedTelephonyTimeZoneSuggestion> - mSuggestionBySlotIndex = new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE); + mTelephonySuggestionsBySlotIndex = + new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE); + + /** + * The latest geolocation suggestion received. + */ + @GuardedBy("this") + private ReferenceWithHistory<GeolocationTimeZoneSuggestion> mLatestGeoLocationSuggestion = + new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE); @GuardedBy("this") private final List<Dumpable> mDumpables = new ArrayList<>(); @@ -284,17 +299,26 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat private static boolean containsAutoTimeDetectionProperties( @NonNull TimeZoneConfiguration configuration) { - return configuration.hasProperty(PROPERTY_AUTO_DETECTION_ENABLED); + return configuration.hasProperty(PROPERTY_AUTO_DETECTION_ENABLED) + || configuration.hasProperty(PROPERTY_GEO_DETECTION_ENABLED); } @Override public synchronized void suggestGeolocationTimeZone( @NonNull GeolocationTimeZoneSuggestion suggestion) { + if (DBG) { + Slog.d(LOG_TAG, "Geolocation suggestion received. newSuggestion=" + suggestion); + } + Objects.requireNonNull(suggestion); + mLatestGeoLocationSuggestion.set(suggestion); - // TODO Implement this. - throw new UnsupportedOperationException( - "Geo-location time zone detection is not currently implemented"); + // Now perform auto time zone detection. The new suggestion may be used to modify the time + // zone setting. + if (mCallback.isGeoDetectionEnabled()) { + String reason = "New geolocation time zone suggested. suggestion=" + suggestion; + doAutoTimeZoneDetection(reason); + } } @Override @@ -332,12 +356,14 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat new QualifiedTelephonyTimeZoneSuggestion(suggestion, score); // Store the suggestion against the correct slotIndex. - mSuggestionBySlotIndex.put(suggestion.getSlotIndex(), scoredSuggestion); + mTelephonySuggestionsBySlotIndex.put(suggestion.getSlotIndex(), scoredSuggestion); // Now perform auto time zone detection. The new suggestion may be used to modify the time // zone setting. - String reason = "New telephony time suggested. suggestion=" + suggestion; - doAutoTimeZoneDetection(reason); + if (!mCallback.isGeoDetectionEnabled()) { + String reason = "New telephony time zone suggested. suggestion=" + suggestion; + doAutoTimeZoneDetection(reason); + } } private static int scoreTelephonySuggestion(@NonNull TelephonyTimeZoneSuggestion suggestion) { @@ -363,9 +389,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat } /** - * Finds the best available time zone suggestion from all slotIndexes. If it is high-enough - * quality and automatic time zone detection is enabled then it will be set on the device. The - * outcome can be that this strategy becomes / remains un-opinionated and nothing is set. + * Performs automatic time zone detection. */ @GuardedBy("this") private void doAutoTimeZoneDetection(@NonNull String detectionReason) { @@ -374,6 +398,62 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat return; } + // Use the right suggestions based on the current configuration. This check is potentially + // race-prone until this value is set via a call to TimeZoneDetectorStrategy. + if (mCallback.isGeoDetectionEnabled()) { + doGeolocationTimeZoneDetection(detectionReason); + } else { + doTelephonyTimeZoneDetection(detectionReason); + } + } + + /** + * Detects the time zone using the latest available geolocation time zone suggestion, if one is + * available. The outcome can be that this strategy becomes / remains un-opinionated and nothing + * is set. + */ + @GuardedBy("this") + private void doGeolocationTimeZoneDetection(@NonNull String detectionReason) { + GeolocationTimeZoneSuggestion latestGeolocationSuggestion = + mLatestGeoLocationSuggestion.get(); + if (latestGeolocationSuggestion == null) { + return; + } + + List<String> zoneIds = latestGeolocationSuggestion.getZoneIds(); + if (zoneIds == null || zoneIds.isEmpty()) { + // This means the client has become uncertain about the time zone or it is certain there + // is no known zone. In either case we must leave the existing time zone setting as it + // is. + return; + } + + // GeolocationTimeZoneSuggestion has no measure of quality. We assume all suggestions are + // reliable. + String zoneId; + + // Introduce bias towards the device's current zone when there are multiple zone suggested. + String deviceTimeZone = mCallback.getDeviceTimeZone(); + if (zoneIds.contains(deviceTimeZone)) { + if (DBG) { + Slog.d(LOG_TAG, + "Geo tz suggestion contains current device time zone. Applying bias."); + } + zoneId = deviceTimeZone; + } else { + zoneId = zoneIds.get(0); + } + setDeviceTimeZoneIfRequired(zoneId, detectionReason); + } + + /** + * Detects the time zone using the latest available telephony time zone suggestions. + * Finds the best available time zone suggestion from all slotIndexes. If it is high-enough + * quality and automatic time zone detection is enabled then it will be set on the device. The + * outcome can be that this strategy becomes / remains un-opinionated and nothing is set. + */ + @GuardedBy("this") + private void doTelephonyTimeZoneDetection(@NonNull String detectionReason) { QualifiedTelephonyTimeZoneSuggestion bestTelephonySuggestion = findBestTelephonySuggestion(); @@ -468,9 +548,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat // slotIndex and find the best. Note that we deliberately do not look at age: the caller can // rate-limit so age is not a strong indicator of confidence. Instead, the callers are // expected to withdraw suggestions they no longer have confidence in. - for (int i = 0; i < mSuggestionBySlotIndex.size(); i++) { + for (int i = 0; i < mTelephonySuggestionsBySlotIndex.size(); i++) { QualifiedTelephonyTimeZoneSuggestion candidateSuggestion = - mSuggestionBySlotIndex.valueAt(i); + mTelephonySuggestionsBySlotIndex.valueAt(i); if (candidateSuggestion == null) { // Unexpected continue; @@ -505,14 +585,10 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat @Override public synchronized void handleAutoTimeZoneConfigChanged() { if (DBG) { - Slog.d(LOG_TAG, "handleTimeZoneDetectionChange() called"); - } - if (mCallback.isAutoDetectionEnabled()) { - // When the user enabled time zone detection, run the time zone detection and change the - // device time zone if possible. - String reason = "Auto time zone detection setting enabled."; - doAutoTimeZoneDetection(reason); + Slog.d(LOG_TAG, "handleAutoTimeZoneConfigChanged()"); } + + doAutoTimeZoneDetection("handleAutoTimeZoneConfigChanged()"); } @Override @@ -532,15 +608,21 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat ipw.println("mCallback.isDeviceTimeZoneInitialized()=" + mCallback.isDeviceTimeZoneInitialized()); ipw.println("mCallback.getDeviceTimeZone()=" + mCallback.getDeviceTimeZone()); + ipw.println("mCallback.isGeoDetectionEnabled()=" + mCallback.isGeoDetectionEnabled()); ipw.println("Time zone change log:"); ipw.increaseIndent(); // level 2 mTimeZoneChangesLog.dump(ipw); ipw.decreaseIndent(); // level 2 + ipw.println("Geolocation suggestion history:"); + ipw.increaseIndent(); // level 2 + mLatestGeoLocationSuggestion.dump(ipw); + ipw.decreaseIndent(); // level 2 + ipw.println("Telephony suggestion history:"); ipw.increaseIndent(); // level 2 - mSuggestionBySlotIndex.dump(ipw); + mTelephonySuggestionsBySlotIndex.dump(ipw); ipw.decreaseIndent(); // level 2 ipw.decreaseIndent(); // level 1 @@ -555,7 +637,15 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat @VisibleForTesting public synchronized QualifiedTelephonyTimeZoneSuggestion getLatestTelephonySuggestion( int slotIndex) { - return mSuggestionBySlotIndex.get(slotIndex); + return mTelephonySuggestionsBySlotIndex.get(slotIndex); + } + + /** + * A method used to inspect strategy state during tests. Not intended for general use. + */ + @VisibleForTesting + public GeolocationTimeZoneSuggestion getLatestGeolocationSuggestion() { + return mLatestGeoLocationSuggestion.get(); } /** diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 2f695c6fd3f1..202a3dcf46dc 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -3070,7 +3070,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub mLockWallpaperMap.put(userId, wallpaper); ensureSaneWallpaperData(wallpaper); } else { - // sanity fallback: we're in bad shape, but establishing a known + // rationality fallback: we're in bad shape, but establishing a known // valid system+lock WallpaperData will keep us from dying. Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!"); wallpaper = new WallpaperData(userId, getWallpaperDir(userId), diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index e573d362fef4..e4f28546a5fd 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -107,6 +107,12 @@ import static android.view.WindowManager.TRANSIT_TASK_CLOSE; import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_UNSET; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.ActivityRecordProto.ALL_DRAWN; @@ -172,12 +178,6 @@ import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchi import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static com.android.server.wm.Task.ActivityState.DESTROYED; @@ -294,6 +294,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.pooled.PooledConsumer; @@ -305,7 +306,6 @@ import com.android.server.am.AppTimeTracker; import com.android.server.am.PendingIntentRecord; import com.android.server.display.color.ColorDisplayService; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriPermissionOwner; import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot; @@ -2549,7 +2549,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final Task stack = getRootTask(); final boolean mayAdjustTop = (isState(RESUMED) || stack.mResumedActivity == null) - && stack.isFocusedStackOnDisplay(); + && stack.isFocusedStackOnDisplay() + // Do not adjust focus task because the task will be reused to launch new activity. + && !task.isClearingToReuseTask(); final boolean shouldAdjustGlobalFocus = mayAdjustTop // It must be checked before {@link #makeFinishingLocked} is called, because a stack // is not visible if it only contains finishing activities. diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index f7cb0146ea52..15e88fc44746 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2023,8 +2023,6 @@ class ActivityStarter { // of history or if it is finished immediately), thus disassociating the task. Also note // that mReuseTask is reset as a result of {@link Task#performClearTaskLocked} // launching another activity. - // TODO(b/36119896): We shouldn't trigger activity launches in this path since we are - // already launching one. targetTask.performClearTaskLocked(); targetTask.setIntent(mStartActivity); mAddingToTask = true; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 31a9c5d4242c..403f225032e9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -5347,15 +5347,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mAmInternal.isBackgroundActivityStartsEnabled(); } - void enableScreenAfterBoot(boolean booted) { - writeBootProgressEnableScreen(SystemClock.uptimeMillis()); - mWindowManager.enableScreenAfterBoot(); - - synchronized (mGlobalLock) { - updateEventDispatchingLocked(booted); - } - } - static long getInputDispatchingTimeoutMillisLocked(ActivityRecord r) { if (r == null || !r.hasProcess()) { return DEFAULT_DISPATCHING_TIMEOUT_MILLIS; @@ -6449,9 +6440,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void enableScreenAfterBoot(boolean booted) { + writeBootProgressEnableScreen(SystemClock.uptimeMillis()); + mWindowManager.enableScreenAfterBoot(); synchronized (mGlobalLock) { - writeBootProgressEnableScreen(SystemClock.uptimeMillis()); - mWindowManager.enableScreenAfterBoot(); updateEventDispatchingLocked(booted); } } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 11a468be8f9f..f76108f332d1 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -67,10 +67,10 @@ import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpe import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation; import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE; import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -127,11 +127,11 @@ import android.view.animation.TranslateAnimation; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.DumpUtils.Dump; import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; import com.android.server.AttributeCache; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.animation.ClipRectLRAnimation; import com.android.server.wm.animation.ClipRectTBAnimation; import com.android.server.wm.animation.CurvedTranslateAnimation; diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 5720e9b7f193..57d51c51c12b 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -41,14 +41,14 @@ import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE; import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN; import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN; import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; @@ -69,7 +69,7 @@ import android.view.WindowManager.TransitionType; import android.view.animation.Animation; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.util.ArrayList; import java.util.LinkedList; diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java index f563e57b363e..0b2c851c4366 100644 --- a/services/core/java/com/android/server/wm/BlackFrame.java +++ b/services/core/java/com/android/server/wm/BlackFrame.java @@ -16,13 +16,13 @@ package com.android.server.wm; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; import android.graphics.Rect; import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.function.Supplier; diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index 6ffb48282017..8bd42f03ff86 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -24,11 +24,11 @@ import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER; import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; import static android.window.DisplayAreaOrganizer.FEATURE_WINDOW_TOKENS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.internal.util.Preconditions.checkState; import static com.android.server.wm.DisplayAreaProto.IS_TASK_DISPLAY_AREA; import static com.android.server.wm.DisplayAreaProto.NAME; import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA; import android.annotation.Nullable; @@ -38,8 +38,8 @@ import android.util.proto.ProtoOutputStream; import android.window.DisplayAreaInfo; import android.window.IDisplayAreaOrganizer; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.util.Comparator; import java.util.function.BiFunction; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index fc170538994c..affbafa095cc 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -74,6 +74,14 @@ import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; import static android.window.DisplayAreaOrganizer.FEATURE_ROOT; import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; @@ -94,14 +102,6 @@ import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA; import static com.android.server.wm.DisplayContentProto.ROTATION; import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION; import static com.android.server.wm.DisplayContentProto.SINGLE_TASK_INSTANCE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_BOOT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.Task.ActivityState.RESUMED; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -203,6 +203,7 @@ import android.view.WindowManagerPolicyConstants.PointerEventListener; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.internal.util.function.TriConsumer; import com.android.internal.util.function.pooled.PooledConsumer; @@ -211,7 +212,6 @@ import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.utils.DisplayRotationUtil; import com.android.server.wm.utils.RotationCache; import com.android.server.wm.utils.WmDisplayCutout; @@ -1557,7 +1557,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // the heavy operations. This also benefits that the states of multiple activities // are handled together. r.linkFixedRotationTransform(prevRotatedLaunchingApp); - setFixedRotationLaunchingAppUnchecked(r, rotation); + if (r != mFixedRotationTransitionListener.mAnimatingRecents) { + // Only update the record for normal activity so the display orientation can be + // updated when the transition is done if it becomes the top. And the case of + // recents can be handled when the recents animation is finished. + setFixedRotationLaunchingAppUnchecked(r, rotation); + } return; } @@ -4063,9 +4068,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG_WM, "Taking screenshot while rotating"); // Send invalid rect and no width and height since it will screenshot the entire display. - Rect frame = new Rect(0, 0, -1, -1); - final Bitmap bitmap = SurfaceControl.screenshot(frame, 0, 0, inRotation, - mDisplay.getRotation()); + final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(displayToken) + .setUseIdentityTransform(inRotation) + .build(); + final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = + SurfaceControl.captureDisplay(captureArgs); + final Bitmap bitmap = screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); if (bitmap == null) { Slog.w(TAG_WM, "Failed to take screenshot"); return null; diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 4f6f75d924c4..2e03cb80b189 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -112,6 +112,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM; import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT; import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON; import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER; @@ -120,7 +121,6 @@ import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -187,6 +187,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.GestureNavigationSettingsObserver; import com.android.internal.policy.ScreenDecorationsUtils; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ScreenshotHelper; import com.android.internal.util.function.TriConsumer; import com.android.internal.view.AppearanceRegion; @@ -199,7 +200,6 @@ import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition; import com.android.server.policy.WindowManagerPolicy.ScreenOnListener; import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs; import com.android.server.policy.WindowOrientationListener; -import com.android.server.protolog.common.ProtoLog; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wallpaper.WallpaperManagerInternal; import com.android.server.wm.utils.InsetUtils; diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index c63128c15e8d..0206787ef226 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -22,8 +22,8 @@ import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -58,12 +58,12 @@ import android.window.WindowContainerTransaction; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.UiThread; import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowOrientationListener; -import com.android.server.protolog.common.ProtoLog; import com.android.server.statusbar.StatusBarManagerInternal; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 22dd1d332345..133b11116460 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -18,11 +18,11 @@ package com.android.server.wm; import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.DragDropController.MSG_ANIMATION_END; import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT; import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -58,9 +58,9 @@ import android.view.WindowManager; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.view.IDragAndDropPermissions; import com.android.server.LocalServices; -import com.android.server.protolog.common.ProtoLog; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index e7fbc334306e..86e2698302aa 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -16,13 +16,13 @@ package com.android.server.wm; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; import android.view.InsetsSource; import android.view.WindowInsets; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 791f47128be0..0fe9735c9e46 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -41,7 +41,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -60,8 +60,8 @@ import android.view.InputEventReceiver; import android.view.InputWindowHandle; import android.view.SurfaceControl; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.Set; diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index f64149cee8c7..d1eb79556d1d 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -24,7 +24,7 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.ViewRootImpl.sNewInsetsMode; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_INSETS_CONTROL; import static com.android.server.wm.WindowManagerService.H.LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED; @@ -40,8 +40,8 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.TriConsumer; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 9c978fd0c867..ab1074ee2821 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -30,7 +30,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; import android.annotation.NonNull; import android.annotation.Nullable; @@ -45,8 +45,8 @@ import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.WindowManager; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.inputmethod.InputMethodManagerInternal; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.ArrayList; @@ -105,6 +105,10 @@ class InsetsStateController { * @return The state stripped of the necessary information. */ InsetsState getInsetsForDispatch(@NonNull WindowState target) { + final InsetsState rotatedState = target.mToken.getFixedRotationTransformInsetsState(); + if (rotatedState != null) { + return rotatedState; + } final InsetsSourceProvider provider = target.getControllableInsetProvider(); final @InternalInsetsType int type = provider != null ? provider.getSource().getType() : ITYPE_INVALID; diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index df5356303f8b..3c64ffb237d6 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -1627,8 +1627,8 @@ class RecentTasks { } if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at " + topIndex + " from intial " + taskIndex); - // Find the end of the chain, doing a sanity check along the way. - boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId; + // Find the end of the chain, doing a validity check along the way. + boolean isValid = top.mAffiliatedTaskId == task.mAffiliatedTaskId; int endIndex = topIndex; Task prev = top; while (endIndex < recentsCount) { @@ -1640,7 +1640,7 @@ class RecentTasks { if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) { Slog.wtf(TAG, "Bad chain @" + endIndex + ": first task has next affiliate: " + prev); - sane = false; + isValid = false; break; } } else { @@ -1652,7 +1652,7 @@ class RecentTasks { + " has bad next affiliate " + cur.mNextAffiliate + " id " + cur.mNextAffiliateTaskId + ", expected " + prev); - sane = false; + isValid = false; break; } } @@ -1662,7 +1662,7 @@ class RecentTasks { Slog.wtf(TAG, "Bad chain @" + endIndex + ": last task " + cur + " has previous affiliate " + cur.mPrevAffiliate); - sane = false; + isValid = false; } if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: end of chain @" + endIndex); break; @@ -1673,7 +1673,7 @@ class RecentTasks { + ": task " + cur + " has previous affiliate " + cur.mPrevAffiliate + " but should be id " + cur.mPrevAffiliate); - sane = false; + isValid = false; break; } } @@ -1682,7 +1682,7 @@ class RecentTasks { + ": task " + cur + " has affiliated id " + cur.mAffiliatedTaskId + " but should be " + task.mAffiliatedTaskId); - sane = false; + isValid = false; break; } prev = cur; @@ -1690,18 +1690,18 @@ class RecentTasks { if (endIndex >= recentsCount) { Slog.wtf(TAG, "Bad chain ran off index " + endIndex + ": last task " + prev); - sane = false; + isValid = false; break; } } - if (sane) { + if (isValid) { if (endIndex < taskIndex) { Slog.wtf(TAG, "Bad chain @" + endIndex + ": did not extend to task " + task + " @" + taskIndex); - sane = false; + isValid = false; } } - if (sane) { + if (isValid) { // All looks good, we can just move all of the affiliated tasks // to the top. for (int i=topIndex; i<=endIndex; i++) { diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index d7b43bc5537d..6c416830b59e 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -25,8 +25,8 @@ import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.WindowManager.TRANSIT_NONE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP; @@ -41,9 +41,9 @@ import android.os.Trace; import android.util.Slog; import android.view.IRecentsAnimationRunner; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks; diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 6b3a5d6bf18c..143fbb0fe48b 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -23,10 +23,10 @@ import static android.view.RemoteAnimationTarget.MODE_OPENING; import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM; import static com.android.server.wm.AnimationAdapterProto.REMOTE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowManagerInternal.AppTransitionListener; @@ -56,12 +56,12 @@ import android.view.SurfaceControl.Transaction; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.SoftInputShowHideReason; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.inputmethod.InputMethodManagerInternal; -import com.android.server.protolog.common.ProtoLog; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index c255a18190f7..e7461e7d5517 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -16,8 +16,8 @@ package com.android.server.wm; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.AnimationAdapterProto.REMOTE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -37,9 +37,9 @@ import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; +import com.android.internal.protolog.ProtoLogImpl; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.FastPrintWriter; -import com.android.server.protolog.ProtoLogImpl; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 1cb483c1d1a0..fe2d08f6a4c2 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -41,6 +41,11 @@ import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY; import static android.view.WindowManager.TRANSIT_TASK_TO_BACK; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.policy.PhoneWindowManager.SYSTEM_DIALOG_REASON_ASSIST; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; @@ -59,11 +64,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATE import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; import static com.android.server.wm.ActivityTaskManagerService.TAG_SWITCH; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT; import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER; @@ -146,6 +146,7 @@ import android.window.WindowContainerToken; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; @@ -155,7 +156,6 @@ import com.android.server.am.ActivityManagerService; import com.android.server.am.AppTimeTracker; import com.android.server.am.UserState; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -737,7 +737,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> winAnimator.mSession.mPid, operation); final long callingIdentity = Binder.clearCallingIdentity(); try { - // There was some problem...first, do a sanity check of the window list to make sure + // There was some problem...first, do a validity check of the window list to make sure // we haven't left any dangling surfaces around. Slog.i(TAG_WM, "Out of memory for surface! Looking for leaks..."); @@ -811,7 +811,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } // "Something has changed! Let's make it correct now." - // TODO: Super crazy long method that should be broken down... + // TODO: Super long method that should be broken down... void performSurfacePlacementNoTrace() { if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by " + Debug.getCallers(3)); diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index d7b8fb00d05c..3c8036d4e3b6 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -18,9 +18,9 @@ package com.android.server.wm; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; import static com.android.server.wm.AnimationSpecProto.ROTATE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; import static com.android.server.wm.RotationAnimationSpecProto.DURATION_MS; import static com.android.server.wm.RotationAnimationSpecProto.END_LUMA; import static com.android.server.wm.RotationAnimationSpecProto.START_LUMA; @@ -50,7 +50,7 @@ import android.view.animation.AnimationUtils; import android.view.animation.Transformation; import com.android.internal.R; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.utils.RotationAnimationUtils; diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 86cbf3e3afe1..3b32a9d76258 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -24,7 +24,7 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -58,7 +58,7 @@ import android.view.SurfaceSession; import android.view.WindowManager; import com.android.internal.os.logging.MetricsLoggerWrapper; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.wm.WindowManagerService.H; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java index 1c9743041923..d9365c5d0666 100644 --- a/services/core/java/com/android/server/wm/SurfaceFreezer.java +++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION; @@ -28,7 +28,7 @@ import android.hardware.HardwareBuffer; import android.view.Surface; import android.view.SurfaceControl; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.util.function.Supplier; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index be0815b06051..0529abf89f6e 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -78,6 +78,8 @@ import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP; import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; @@ -116,8 +118,6 @@ import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_ import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.Task.ActivityState.PAUSED; import static com.android.server.wm.Task.ActivityState.PAUSING; import static com.android.server.wm.Task.ActivityState.RESUMED; @@ -210,6 +210,7 @@ import android.window.ITaskOrganizer; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; @@ -218,7 +219,6 @@ import com.android.internal.util.function.pooled.PooledPredicate; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService; import com.android.server.am.AppTimeTracker; -import com.android.server.protolog.common.ProtoLog; import com.android.server.uri.NeededUriGrants; import org.xmlpull.v1.XmlPullParser; @@ -1836,14 +1836,25 @@ class Task extends WindowContainer<WindowContainer> { */ void performClearTaskLocked() { mReuseTask = true; - performClearTask("clear-task-all"); - mReuseTask = false; + mStackSupervisor.beginDeferResume(); + try { + performClearTask("clear-task-all"); + } finally { + mStackSupervisor.endDeferResume(); + mReuseTask = false; + } } ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) { mReuseTask = true; - final ActivityRecord result = performClearTaskLocked(newR, launchFlags); - mReuseTask = false; + mStackSupervisor.beginDeferResume(); + final ActivityRecord result; + try { + result = performClearTaskLocked(newR, launchFlags); + } finally { + mStackSupervisor.endDeferResume(); + mReuseTask = false; + } return result; } @@ -7056,17 +7067,21 @@ class Task extends WindowContainer<WindowContainer> { /** * Reset local parameters because an app's activity died. * @param app The app of the activity that died. + * @return {@code true} if the process of the pausing activity is died. */ - void handleAppDied(WindowProcessController app) { + boolean handleAppDied(WindowProcessController app) { + boolean isPausingDied = false; if (mPausingActivity != null && mPausingActivity.app == app) { if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE, "App died while pausing: " + mPausingActivity); mPausingActivity = null; + isPausingDied = true; } if (mLastPausedActivity != null && mLastPausedActivity.app == app) { mLastPausedActivity = null; mLastNoHistoryActivity = null; } + return isPausingDied; } boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index a847744247c7..32511108836e 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -32,13 +32,13 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK; import static com.android.server.wm.DisplayContent.alwaysCreateStack; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.RootWindowContainer.TAG_STATES; import static com.android.server.wm.Task.ActivityState.RESUMED; import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE; @@ -58,10 +58,10 @@ import android.view.SurfaceControl; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 3fbc0373e1a9..a66cd846e8be 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -26,8 +26,8 @@ import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_LEFT; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -59,7 +59,7 @@ import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.TaskResizingAlgorithm; import com.android.internal.policy.TaskResizingAlgorithm.CtrlType; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; class TaskPositioner implements IBinder.DeathRecipient { private static final boolean DEBUG_ORIENTATION_VIOLATIONS = false; diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java index 1103bf19b3bf..3def0911bd76 100644 --- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java +++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java @@ -15,14 +15,14 @@ */ package com.android.server.wm; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import android.hardware.HardwareBuffer; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.util.function.Function; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 68445f6970fb..dbbb7ff69b3b 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -27,7 +27,6 @@ import android.annotation.Nullable; import android.app.ActivityManager.TaskSnapshot; import android.content.pm.PackageManager; import android.graphics.Bitmap; -import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.RecordingCanvas; @@ -82,7 +81,7 @@ class TaskSnapshotController { /** * Return value for {@link #getSnapshotMode}: We are not allowed to take a real screenshot but - * we should try to use the app theme to create a dummy representation of the app. + * we should try to use the app theme to create a fake representation of the app. */ @VisibleForTesting static final int SNAPSHOT_MODE_APP_THEME = 1; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index 9b18ac8f7702..e9ada6be7e7b 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -41,7 +41,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.getNavigationBarRect; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.TaskSnapshotController.getSystemBarInsets; import static com.android.server.wm.TaskSnapshotController.mergeInsetsSources; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -83,9 +83,9 @@ import android.view.WindowManagerGlobal; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.DecorView; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.view.BaseIWindow; import com.android.server.policy.WindowManagerPolicy.StartingSurface; -import com.android.server.protolog.common.ProtoLog; /** * This class represents a starting window that shows a snapshot. diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java index f46701536cf8..38bff9ed3c31 100644 --- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java +++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java @@ -15,8 +15,8 @@ */ package com.android.server.wm; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.AnimationAdapterProto.REMOTE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; @@ -26,7 +26,7 @@ import android.util.proto.ProtoOutputStream; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.AnimationType; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 6377a2169b34..5c6266a2f8c4 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; @@ -36,8 +36,8 @@ import android.util.TimeUtils; import android.view.Choreographer; import android.view.SurfaceControl; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index e24d185557e8..8a5e70f2e353 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -28,14 +28,14 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.UserHandle.USER_NULL; import static android.view.SurfaceControl.Transaction; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; @@ -82,8 +82,8 @@ import android.window.IWindowContainerToken; import android.window.WindowContainerToken; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.Animatable; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java index b75f886520e6..b9f67a590c2a 100644 --- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java +++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java @@ -19,7 +19,7 @@ package com.android.server.wm; import static android.view.SurfaceControl.METADATA_OWNER_UID; import static android.view.SurfaceControl.METADATA_WINDOW_TYPE; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowContainerThumbnailProto.HEIGHT; import static com.android.server.wm.WindowContainerThumbnailProto.SURFACE_ANIMATOR; @@ -39,7 +39,7 @@ import android.view.SurfaceControl.Builder; import android.view.SurfaceControl.Transaction; import android.view.animation.Animation; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.Animatable; import com.android.server.wm.SurfaceAnimator.AnimationType; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0b1d6bc0adfd..7624d4c1ea36 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -84,22 +84,22 @@ import static android.view.WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC; import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; +import static com.android.internal.protolog.ProtoLogGroup.WM_ERROR; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN; import static com.android.server.LockGuard.INDEX_WINDOW; import static com.android.server.LockGuard.installLock; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_BOOT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; -import static com.android.server.wm.ProtoLogGroup.WM_ERROR; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -265,6 +265,8 @@ import com.android.internal.os.IResultReceiver; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; import com.android.internal.policy.KeyInterceptionInfo; +import com.android.internal.protolog.ProtoLogImpl; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.LatencyTracker; @@ -281,8 +283,6 @@ import com.android.server.input.InputManagerService; import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowManagerPolicy.ScreenOffListener; import com.android.server.power.ShutdownThread; -import com.android.server.protolog.ProtoLogImpl; -import com.android.server.protolog.common.ProtoLog; import com.android.server.utils.PriorityDump; import com.android.server.wm.utils.DeviceConfigInterface; @@ -3612,7 +3612,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (SHOW_VERBOSE_TRANSACTIONS) Slog.i(TAG_WM, ">>> showStrictModeViolation"); - // TODO: Modify this to use the surface trace once it is not going crazy. + // TODO: Modify this to use the surface trace once it is not going baffling. // b/31532461 // TODO(multi-display): support multiple displays if (mStrictModeFlash == null) { diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index bdecb8d99752..271d2b1a002f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -31,7 +31,7 @@ import android.view.Surface; import android.view.ViewDebug; import com.android.internal.os.ByteTransferPipe; -import com.android.server.protolog.ProtoLogImpl; +import com.android.internal.protolog.ProtoLogImpl; import java.io.IOException; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 70c30c9180d7..c714eeb92e68 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -196,7 +196,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio private final Configuration mLastReportedConfiguration = new Configuration(); // Configuration that is waiting to be dispatched to the process. private Configuration mPendingConfiguration; - private final Configuration mNewOverrideConfig = new Configuration(); // Registered display id as a listener to override config change private int mDisplayId; private ActivityRecord mConfigActivityRecord; @@ -1201,7 +1200,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio final Task rootTask = r.getRootTask(); if (rootTask != null) { - rootTask.handleAppDied(this); + // There may be a pausing activity that hasn't shown any window and was requested + // to be hidden. But pausing is also a visible state, it should be regarded as + // visible, so the caller can know the next activity should be resumed. + hasVisibleActivities |= rootTask.handleAppDied(this); } r.handleAppDied(); } @@ -1289,11 +1291,26 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } @Override + public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) { + super.onRequestedOverrideConfigurationChanged( + sanitizeProcessConfiguration(overrideConfiguration)); + } + + @Override public void onMergedOverrideConfigurationChanged(Configuration mergedOverrideConfig) { + super.onRequestedOverrideConfigurationChanged( + sanitizeProcessConfiguration(mergedOverrideConfig)); + } + + private static Configuration sanitizeProcessConfiguration(Configuration config) { // Make sure that we don't accidentally override the activity type. - mNewOverrideConfig.setTo(mergedOverrideConfig); - mNewOverrideConfig.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED); - super.onRequestedOverrideConfigurationChanged(mNewOverrideConfig); + if (config.windowConfiguration.getActivityType() != ACTIVITY_TYPE_UNDEFINED) { + final Configuration sanitizedConfig = new Configuration(config); + sanitizedConfig.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED); + return sanitizedConfig; + } + + return config; } private void updateConfiguration() { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ab78e74b9e37..49e623d8dd11 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -101,6 +101,14 @@ import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFO import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME; import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RESIZE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.am.ActivityManagerService.MY_PID; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER; @@ -116,14 +124,6 @@ import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.MoveAnimationSpecProto.DURATION_MS; import static com.android.server.wm.MoveAnimationSpecProto.FROM; import static com.android.server.wm.MoveAnimationSpecProto.TO; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RESIZE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -236,10 +236,10 @@ import android.view.animation.Interpolator; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.KeyInterceptionInfo; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.ToBooleanFunction; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.utils.WmDisplayCutout; @@ -1535,10 +1535,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } InsetsState getInsetsState() { - final InsetsState insetsState = mToken.getFixedRotationTransformInsetsState(); - if (insetsState != null) { - return insetsState; - } return getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this); } @@ -2460,9 +2456,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP finishInputEvent(event, true); } } - /** - * Dummy event receiver for windows that died visible. - */ + /** Fake event receiver for windows that died visible. */ private DeadWindowEventReceiver mDeadWindowEventReceiver; void openInputChannel(InputChannel outInputChannel) { @@ -2480,9 +2474,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mClientChannel.dispose(); mClientChannel = null; } else { - // If the window died visible, we setup a dummy input channel, so that taps + // If the window died visible, we setup a fake input channel, so that taps // can still detected by input monitor channel, and we can relaunch the app. - // Create dummy event receiver that simply reports all events as handled. + // Create fake event receiver that simply reports all events as handled. mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel); } mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index d0101adaabad..92177abbbf85 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -31,13 +31,13 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.TRANSIT_NONE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_DRAW; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_DRAW; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; @@ -76,8 +76,8 @@ import android.view.WindowManager.LayoutParams; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; @@ -560,9 +560,9 @@ class WindowStateAnimator { } } - // Something is wrong and SurfaceFlinger will not like this, try to revert to sane values. - // This doesn't necessarily mean that there is an error in the system. The sizes might be - // incorrect, because it is before the first layout or draw. + // Something is wrong and SurfaceFlinger will not like this, try to revert to reasonable + // values. This doesn't necessarily mean that there is an error in the system. The sizes + // might be incorrect, because it is before the first layout or draw. if (outSize.width() < 1) { outSize.right = 1; } diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index b89cdd32e132..9b40822c8ab5 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -21,8 +21,8 @@ import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW; import static android.view.SurfaceControl.METADATA_OWNER_UID; import static android.view.SurfaceControl.METADATA_WINDOW_TYPE; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -40,7 +40,7 @@ import android.view.SurfaceControl; import android.view.WindowContentFrameStats; import android.view.WindowManager; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 2c1bb3ec51eb..bc4d9a973ecb 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -23,10 +23,10 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; -import static com.android.server.wm.ProtoLogGroup.WM_ERROR; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; +import static com.android.internal.protolog.ProtoLogGroup.WM_ERROR; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -59,8 +59,8 @@ import android.view.SurfaceControl; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.ArrayList; @@ -548,7 +548,7 @@ class WindowToken extends WindowContainer<WindowState> { void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, Configuration config) { if (mFixedRotationTransformState != null) { - return; + cleanUpFixedRotationTransformState(true /* replacing */); } mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames, new Configuration(config), mDisplayContent.getRotation()); @@ -565,13 +565,13 @@ class WindowToken extends WindowContainer<WindowState> { * one. This takes the same effect as {@link #applyFixedRotationTransform}. */ void linkFixedRotationTransform(WindowToken other) { - if (mFixedRotationTransformState != null) { - return; - } final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState; - if (fixedRotationState == null) { + if (fixedRotationState == null || mFixedRotationTransformState == fixedRotationState) { return; } + if (mFixedRotationTransformState != null) { + cleanUpFixedRotationTransformState(true /* replacing */); + } mFixedRotationTransformState = fixedRotationState; fixedRotationState.mAssociatedTokens.add(this); onConfigurationChanged(getParent().getConfiguration()); @@ -626,11 +626,17 @@ class WindowToken extends WindowContainer<WindowState> { // The state is cleared at the end, because it is used to indicate that other windows can // use seamless rotation when applying rotation to display. for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) { - state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState(); + state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState( + false /* replacing */); } } - private void cleanUpFixedRotationTransformState() { + private void cleanUpFixedRotationTransformState(boolean replacing) { + if (replacing && mFixedRotationTransformState.mAssociatedTokens.size() > 1) { + // The state is not only used by self. Make sure to leave the influence by others. + mFixedRotationTransformState.mAssociatedTokens.remove(this); + mFixedRotationTransformState.mRotatedContainers.remove(this); + } mFixedRotationTransformState = null; notifyFixedRotationTransform(false /* enabled */); } diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java index ba3dc607f6cc..e8b8bfce21a3 100644 --- a/services/core/java/com/android/server/wm/WindowTracing.java +++ b/services/core/java/com/android/server/wm/WindowTracing.java @@ -34,7 +34,7 @@ import android.util.Log; import android.util.proto.ProtoOutputStream; import android.view.Choreographer; -import com.android.server.protolog.ProtoLogImpl; +import com.android.internal.protolog.ProtoLogImpl; import com.android.internal.util.TraceBuffer; import java.io.File; diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index b6633ced771b..529fb8838aa1 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -17,9 +17,7 @@ #define LOG_TAG "VibratorService" #include <android/hardware/vibrator/1.3/IVibrator.h> -#include <android/hardware/vibrator/BnVibratorCallback.h> #include <android/hardware/vibrator/IVibrator.h> -#include <binder/IServiceManager.h> #include "jni.h" #include <nativehelper/JNIHelp.h> @@ -28,19 +26,11 @@ #include <utils/misc.h> #include <utils/Log.h> -#include <hardware/vibrator.h> #include <inttypes.h> -#include <stdio.h> #include <vibratorservice/VibratorHalController.h> -using android::hardware::Return; -using android::hardware::Void; -using android::hardware::vibrator::V1_0::EffectStrength; -using android::hardware::vibrator::V1_0::Status; -using android::hardware::vibrator::V1_1::Effect_1_1; - namespace V1_0 = android::hardware::vibrator::V1_0; namespace V1_1 = android::hardware::vibrator::V1_1; namespace V1_2 = android::hardware::vibrator::V1_2; @@ -87,150 +77,7 @@ static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) == static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) == static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK)); -class VibratorCallback { - public: - VibratorCallback(JNIEnv *env, jobject vibration) : - mVibration(MakeGlobalRefOrDie(env, vibration)) {} - - ~VibratorCallback() { - JNIEnv *env = AndroidRuntime::getJNIEnv(); - env->DeleteGlobalRef(mVibration); - } - - void onComplete() { - auto env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod(mVibration, sMethodIdOnComplete); - } - - private: - jobject mVibration; -}; - -class AidlVibratorCallback : public aidl::BnVibratorCallback { - public: - AidlVibratorCallback(JNIEnv *env, jobject vibration) : - mCb(env, vibration) {} - - binder::Status onComplete() override { - mCb.onComplete(); - return binder::Status::ok(); // oneway, local call - } - - private: - VibratorCallback mCb; -}; - -static constexpr int NUM_TRIES = 2; - -template<class R> -inline R NoneStatus() { - using ::android::hardware::Status; - return Status::fromExceptionCode(Status::EX_NONE); -} - -template<> -inline binder::Status NoneStatus() { - using binder::Status; - return Status::fromExceptionCode(Status::EX_NONE); -} - -// Creates a Return<R> with STATUS::EX_NULL_POINTER. -template<class R> -inline R NullptrStatus() { - using ::android::hardware::Status; - return Status::fromExceptionCode(Status::EX_NULL_POINTER); -} - -template<> -inline binder::Status NullptrStatus() { - using binder::Status; - return Status::fromExceptionCode(Status::EX_NULL_POINTER); -} - -template <typename I> -sp<I> getService() { - return I::getService(); -} - -template <> -sp<aidl::IVibrator> getService() { - return waitForVintfService<aidl::IVibrator>(); -} - -template <typename I> -sp<I> tryGetService() { - return I::tryGetService(); -} - -template <> -sp<aidl::IVibrator> tryGetService() { - return checkVintfService<aidl::IVibrator>(); -} - -template <typename I> -class HalWrapper { - public: - static std::unique_ptr<HalWrapper> Create() { - // Assume that if getService returns a nullptr, HAL is not available on the - // device. - auto hal = getService<I>(); - return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr; - } - - // Helper used to transparently deal with the vibrator HAL becoming unavailable. - template<class R, class... Args0, class... Args1> - R call(R (I::* fn)(Args0...), Args1&&... args1) { - // Return<R> doesn't have a default constructor, so make a Return<R> with - // STATUS::EX_NONE. - R ret{NoneStatus<R>()}; - - // Note that ret is guaranteed to be changed after this loop. - for (int i = 0; i < NUM_TRIES; ++i) { - ret = (mHal == nullptr) ? NullptrStatus<R>() - : (*mHal.*fn)(std::forward<Args1>(args1)...); - - if (ret.isOk()) { - break; - } - - ALOGE("Failed to issue command to vibrator HAL. Retrying."); - - // Restoring connection to the HAL. - mHal = tryGetService<I>(); - } - return ret; - } - - private: - HalWrapper(sp<I> &&hal) : mHal(std::move(hal)) {} - - private: - sp<I> mHal; -}; - -template <typename I> -static auto getHal() { - static auto sHalWrapper = HalWrapper<I>::Create(); - return sHalWrapper.get(); -} - -template<class R, class I, class... Args0, class... Args1> -R halCall(R (I::* fn)(Args0...), Args1&&... args1) { - auto hal = getHal<I>(); - return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>(); -} - -template<class R> -bool isValidEffect(jlong effect) { - if (effect < 0) { - return false; - } - R val = static_cast<R>(effect); - auto iter = hardware::hidl_enum_range<R>(); - return val >= *iter.begin() && val <= *std::prev(iter.end()); -} - -static void callVibrationOnComplete(jobject vibration) { +static inline void callVibrationOnComplete(jobject vibration) { if (vibration == nullptr) { return; } @@ -257,14 +104,6 @@ static void destroyVibratorController(void* rawVibratorController) { } static jlong vibratorInit(JNIEnv* /* env */, jclass /* clazz */) { - if (auto hal = getHal<aidl::IVibrator>()) { - // IBinder::pingBinder isn't accessible as a pointer function - // but getCapabilities can serve the same purpose - int32_t cap; - hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk(); - } else { - halCall(&V1_0::IVibrator::ping).isOk(); - } std::unique_ptr<vibrator::HalController> controller = std::make_unique<vibrator::HalController>(); controller->init(); @@ -342,70 +181,19 @@ static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jl return effects; } -static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong effect, jlong strength, - jobject vibration, jboolean withCallback) { - if (auto hal = getHal<aidl::IVibrator>()) { - int32_t lengthMs; - sp<AidlVibratorCallback> effectCallback = - (withCallback != JNI_FALSE ? new AidlVibratorCallback(env, vibration) : nullptr); - aidl::Effect effectType(static_cast<aidl::Effect>(effect)); - aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength)); - - auto status = hal->call(&aidl::IVibrator::perform, effectType, effectStrength, effectCallback, &lengthMs); - if (!status.isOk()) { - if (status.exceptionCode() != binder::Status::EX_UNSUPPORTED_OPERATION) { - ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32 - ": %s", static_cast<int64_t>(effect), static_cast<int32_t>(strength), status.toString8().string()); - } - return -1; - } - return lengthMs; - } else { - Status status; - uint32_t lengthMs; - auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) { - status = retStatus; - lengthMs = retLengthMs; - }; - EffectStrength effectStrength(static_cast<EffectStrength>(strength)); - - Return<void> ret; - if (isValidEffect<V1_0::Effect>(effect)) { - ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect), - effectStrength, callback); - } else if (isValidEffect<Effect_1_1>(effect)) { - ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect), - effectStrength, callback); - } else if (isValidEffect<V1_2::Effect>(effect)) { - ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect), - effectStrength, callback); - } else if (isValidEffect<V1_3::Effect>(effect)) { - ret = halCall(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(effect), - effectStrength, callback); - } else { - ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")", - static_cast<int32_t>(effect)); - return -1; - } - - if (!ret.isOk()) { - ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect)); - return -1; - } - - if (status == Status::OK) { - return lengthMs; - } else if (status != Status::UNSUPPORTED_OPERATION) { - // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor - // doesn't have a pre-defined waveform to perform for it, so we should just give the - // opportunity to fall back to the framework waveforms. - ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32 - ", error=%" PRIu32 ").", static_cast<int64_t>(effect), - static_cast<int32_t>(strength), static_cast<uint32_t>(status)); - } +static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, + jlong effect, jlong strength, jobject vibration) { + vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); + if (controller == nullptr) { + ALOGE("vibratorPerformEffect failed because controller was not initialized"); + return -1; } - - return -1; + aidl::Effect effectType = static_cast<aidl::Effect>(effect); + aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength); + jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration); + auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); }; + auto result = controller->performEffect(effectType, effectStrength, callback); + return result.isOk() ? result.value().count() : -1; } static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, @@ -464,7 +252,7 @@ static const JNINativeMethod method_table[] = { {"vibratorOn", "(JJLcom/android/server/VibratorService$Vibration;)V", (void*)vibratorOn}, {"vibratorOff", "(J)V", (void*)vibratorOff}, {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude}, - {"vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;Z)J", + {"vibratorPerformEffect", "(JJJLcom/android/server/VibratorService$Vibration;)J", (void*)vibratorPerformEffect}, {"vibratorPerformComposedEffect", "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/" diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java new file mode 100644 index 000000000000..6fea2aaf728b --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java @@ -0,0 +1,1116 @@ +/* + * Copyright (C) 2020 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.devicepolicy; + +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + +import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.END_TAG; +import static org.xmlpull.v1.XmlPullParser.TEXT; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.admin.DeviceAdminInfo; +import android.app.admin.DevicePolicyManager; +import android.app.admin.FactoryResetProtectionPolicy; +import android.app.admin.PasswordPolicy; +import android.graphics.Color; +import android.os.Bundle; +import android.os.PersistableBundle; +import android.os.UserHandle; +import android.os.UserManager; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Log; +import android.util.Slog; + +import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; +import com.android.internal.util.XmlUtils; +import com.android.server.pm.UserRestrictionsUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; + +class ActiveAdmin { + private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features"; + private static final String TAG_TEST_ONLY_ADMIN = "test-only-admin"; + private static final String TAG_DISABLE_CAMERA = "disable-camera"; + private static final String TAG_DISABLE_CALLER_ID = "disable-caller-id"; + private static final String TAG_DISABLE_CONTACTS_SEARCH = "disable-contacts-search"; + private static final String TAG_DISABLE_BLUETOOTH_CONTACT_SHARING = + "disable-bt-contacts-sharing"; + private static final String TAG_DISABLE_SCREEN_CAPTURE = "disable-screen-capture"; + private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management"; + private static final String TAG_REQUIRE_AUTO_TIME = "require_auto_time"; + private static final String TAG_FORCE_EPHEMERAL_USERS = "force_ephemeral_users"; + private static final String TAG_IS_NETWORK_LOGGING_ENABLED = "is_network_logging_enabled"; + private static final String TAG_ACCOUNT_TYPE = "account-type"; + private static final String TAG_PERMITTED_ACCESSIBILITY_SERVICES = + "permitted-accessiblity-services"; + private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested"; + private static final String TAG_MANAGE_TRUST_AGENT_FEATURES = "manage-trust-agent-features"; + private static final String TAG_TRUST_AGENT_COMPONENT_OPTIONS = "trust-agent-component-options"; + private static final String TAG_TRUST_AGENT_COMPONENT = "component"; + private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date"; + private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout"; + private static final String TAG_GLOBAL_PROXY_EXCLUSION_LIST = "global-proxy-exclusion-list"; + private static final String TAG_GLOBAL_PROXY_SPEC = "global-proxy-spec"; + private static final String TAG_SPECIFIES_GLOBAL_PROXY = "specifies-global-proxy"; + private static final String TAG_PERMITTED_IMES = "permitted-imes"; + private static final String TAG_PERMITTED_NOTIFICATION_LISTENERS = + "permitted-notification-listeners"; + private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe"; + private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock"; + private static final String TAG_STRONG_AUTH_UNLOCK_TIMEOUT = "strong-auth-unlock-timeout"; + private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter"; + private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols"; + private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric"; + private static final String TAG_MIN_PASSWORD_LETTERS = "min-password-letters"; + private static final String TAG_MIN_PASSWORD_LOWERCASE = "min-password-lowercase"; + private static final String TAG_MIN_PASSWORD_UPPERCASE = "min-password-uppercase"; + private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length"; + private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length"; + private static final String TAG_PASSWORD_QUALITY = "password-quality"; + private static final String TAG_POLICIES = "policies"; + private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS = + "cross-profile-widget-providers"; + private static final String TAG_PROVIDER = "provider"; + private static final String TAG_PACKAGE_LIST_ITEM = "item"; + private static final String TAG_KEEP_UNINSTALLED_PACKAGES = "keep-uninstalled-packages"; + private static final String TAG_USER_RESTRICTIONS = "user-restrictions"; + private static final String TAG_DEFAULT_ENABLED_USER_RESTRICTIONS = + "default-enabled-user-restrictions"; + private static final String TAG_RESTRICTION = "restriction"; + private static final String TAG_SHORT_SUPPORT_MESSAGE = "short-support-message"; + private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message"; + private static final String TAG_PARENT_ADMIN = "parent-admin"; + private static final String TAG_ORGANIZATION_COLOR = "organization-color"; + private static final String TAG_ORGANIZATION_NAME = "organization-name"; + private static final String TAG_IS_LOGOUT_ENABLED = "is_logout_enabled"; + private static final String TAG_START_USER_SESSION_MESSAGE = "start_user_session_message"; + private static final String TAG_END_USER_SESSION_MESSAGE = "end_user_session_message"; + private static final String TAG_METERED_DATA_DISABLED_PACKAGES = + "metered_data_disabled_packages"; + private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES = + "cross-profile-calendar-packages"; + private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL = + "cross-profile-calendar-packages-null"; + private static final String TAG_CROSS_PROFILE_PACKAGES = "cross-profile-packages"; + private static final String TAG_FACTORY_RESET_PROTECTION_POLICY = + "factory_reset_protection_policy"; + private static final String TAG_SUSPEND_PERSONAL_APPS = "suspend-personal-apps"; + private static final String TAG_PROFILE_MAXIMUM_TIME_OFF = "profile-max-time-off"; + private static final String TAG_PROFILE_OFF_DEADLINE = "profile-off-deadline"; + private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn-package"; + private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown"; + private static final String TAG_COMMON_CRITERIA_MODE = "common-criteria-mode"; + private static final String ATTR_VALUE = "value"; + private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification"; + private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications"; + + DeviceAdminInfo info; + + static final int DEF_PASSWORD_HISTORY_LENGTH = 0; + int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH; + + @NonNull + PasswordPolicy mPasswordPolicy = new PasswordPolicy(); + + @Nullable + FactoryResetProtectionPolicy mFactoryResetProtectionPolicy = null; + + static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0; + long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK; + + long strongAuthUnlockTimeout = 0; // admin doesn't participate by default + + static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0; + int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE; + + static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0; + long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT; + + static final long DEF_PASSWORD_EXPIRATION_DATE = 0; + long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE; + + static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none + + int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED; + + boolean encryptionRequested = false; + boolean testOnlyAdmin = false; + boolean disableCamera = false; + boolean disableCallerId = false; + boolean disableContactsSearch = false; + boolean disableBluetoothContactSharing = true; + boolean disableScreenCapture = false; + boolean requireAutoTime = false; + boolean forceEphemeralUsers = false; + boolean isNetworkLoggingEnabled = false; + boolean isLogoutEnabled = false; + + // one notification after enabling + one more after reboots + static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 2; + int numNetworkLoggingNotifications = 0; + long lastNetworkLoggingNotificationTimeMs = 0; // Time in milliseconds since epoch + + ActiveAdmin parentAdmin; + final boolean isParent; + + static class TrustAgentInfo { + public PersistableBundle options; + TrustAgentInfo(PersistableBundle bundle) { + options = bundle; + } + } + + // The list of packages which are not allowed to use metered data. + List<String> meteredDisabledPackages; + + final Set<String> accountTypesWithManagementDisabled = new ArraySet<>(); + + // The list of permitted accessibility services package namesas set by a profile + // or device owner. Null means all accessibility services are allowed, empty means + // none except system services are allowed. + List<String> permittedAccessiblityServices; + + // The list of permitted input methods package names as set by a profile or device owner. + // Null means all input methods are allowed, empty means none except system imes are + // allowed. + List<String> permittedInputMethods; + + // The list of packages allowed to use a NotificationListenerService to receive events for + // notifications from this user. Null means that all packages are allowed. Empty list means + // that only packages from the system are allowed. + List<String> permittedNotificationListeners; + + // List of package names to keep cached. + List<String> keepUninstalledPackages; + + // TODO: review implementation decisions with frameworks team + boolean specifiesGlobalProxy = false; + String globalProxySpec = null; + String globalProxyExclusionList = null; + + @NonNull + ArrayMap<String, TrustAgentInfo> trustAgentInfos = new ArrayMap<>(); + + List<String> crossProfileWidgetProviders; + + Bundle userRestrictions; + + // User restrictions that have already been enabled by default for this admin (either when + // setting the device or profile owner, or during a system update if one of those "enabled + // by default" restrictions is newly added). + final Set<String> defaultEnabledRestrictionsAlreadySet = new ArraySet<>(); + + // Support text provided by the admin to display to the user. + CharSequence shortSupportMessage = null; + CharSequence longSupportMessage = null; + + // Background color of confirm credentials screen. Default: teal. + static final int DEF_ORGANIZATION_COLOR = Color.parseColor("#00796B"); + int organizationColor = DEF_ORGANIZATION_COLOR; + + // Default title of confirm credentials screen + String organizationName = null; + + // Message for user switcher + String startUserSessionMessage = null; + String endUserSessionMessage = null; + + // The allow list of packages that can access cross profile calendar APIs. + // This allow list should be in default an empty list, which indicates that no package + // is allow listed. + List<String> mCrossProfileCalendarPackages = Collections.emptyList(); + + // The allow list of packages that the admin has enabled to be able to request consent from + // the user to communicate cross-profile. By default, no packages are allowed, which is + // represented as an empty list. + List<String> mCrossProfilePackages = Collections.emptyList(); + + // Whether the admin explicitly requires personal apps to be suspended + boolean mSuspendPersonalApps = false; + // Maximum time the profile owned by this admin can be off. + long mProfileMaximumTimeOffMillis = 0; + // Time by which the profile should be turned on according to System.currentTimeMillis(). + long mProfileOffDeadline = 0; + + public String mAlwaysOnVpnPackage; + public boolean mAlwaysOnVpnLockdown; + boolean mCommonCriteriaMode; + + ActiveAdmin(DeviceAdminInfo info, boolean isParent) { + this.info = info; + this.isParent = isParent; + } + + ActiveAdmin getParentActiveAdmin() { + Preconditions.checkState(!isParent); + + if (parentAdmin == null) { + parentAdmin = new ActiveAdmin(info, /* parent */ true); + } + return parentAdmin; + } + + boolean hasParentActiveAdmin() { + return parentAdmin != null; + } + + int getUid() { + return info.getActivityInfo().applicationInfo.uid; + } + + public UserHandle getUserHandle() { + return UserHandle.of(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid)); + } + + void writeToXml(XmlSerializer out) + throws IllegalArgumentException, IllegalStateException, IOException { + out.startTag(null, TAG_POLICIES); + info.writePoliciesToXml(out); + out.endTag(null, TAG_POLICIES); + if (mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED) { + writeAttributeValueToXml( + out, TAG_PASSWORD_QUALITY, mPasswordPolicy.quality); + if (mPasswordPolicy.length != PasswordPolicy.DEF_MINIMUM_LENGTH) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_LENGTH, mPasswordPolicy.length); + } + if (mPasswordPolicy.upperCase != PasswordPolicy.DEF_MINIMUM_UPPER_CASE) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_UPPERCASE, mPasswordPolicy.upperCase); + } + if (mPasswordPolicy.lowerCase != PasswordPolicy.DEF_MINIMUM_LOWER_CASE) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_LOWERCASE, mPasswordPolicy.lowerCase); + } + if (mPasswordPolicy.letters != PasswordPolicy.DEF_MINIMUM_LETTERS) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_LETTERS, mPasswordPolicy.letters); + } + if (mPasswordPolicy.numeric != PasswordPolicy.DEF_MINIMUM_NUMERIC) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_NUMERIC, mPasswordPolicy.numeric); + } + if (mPasswordPolicy.symbols != PasswordPolicy.DEF_MINIMUM_SYMBOLS) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_SYMBOLS, mPasswordPolicy.symbols); + } + if (mPasswordPolicy.nonLetter > PasswordPolicy.DEF_MINIMUM_NON_LETTER) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_NONLETTER, mPasswordPolicy.nonLetter); + } + } + if (passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) { + writeAttributeValueToXml( + out, TAG_PASSWORD_HISTORY_LENGTH, passwordHistoryLength); + } + if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) { + writeAttributeValueToXml( + out, TAG_MAX_TIME_TO_UNLOCK, maximumTimeToUnlock); + } + if (strongAuthUnlockTimeout != DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) { + writeAttributeValueToXml( + out, TAG_STRONG_AUTH_UNLOCK_TIMEOUT, strongAuthUnlockTimeout); + } + if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) { + writeAttributeValueToXml( + out, TAG_MAX_FAILED_PASSWORD_WIPE, maximumFailedPasswordsForWipe); + } + if (specifiesGlobalProxy) { + writeAttributeValueToXml( + out, TAG_SPECIFIES_GLOBAL_PROXY, specifiesGlobalProxy); + if (globalProxySpec != null) { + writeAttributeValueToXml(out, TAG_GLOBAL_PROXY_SPEC, globalProxySpec); + } + if (globalProxyExclusionList != null) { + writeAttributeValueToXml( + out, TAG_GLOBAL_PROXY_EXCLUSION_LIST, globalProxyExclusionList); + } + } + if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) { + writeAttributeValueToXml( + out, TAG_PASSWORD_EXPIRATION_TIMEOUT, passwordExpirationTimeout); + } + if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) { + writeAttributeValueToXml( + out, TAG_PASSWORD_EXPIRATION_DATE, passwordExpirationDate); + } + if (encryptionRequested) { + writeAttributeValueToXml( + out, TAG_ENCRYPTION_REQUESTED, encryptionRequested); + } + if (testOnlyAdmin) { + writeAttributeValueToXml( + out, TAG_TEST_ONLY_ADMIN, testOnlyAdmin); + } + if (disableCamera) { + writeAttributeValueToXml( + out, TAG_DISABLE_CAMERA, disableCamera); + } + if (disableCallerId) { + writeAttributeValueToXml( + out, TAG_DISABLE_CALLER_ID, disableCallerId); + } + if (disableContactsSearch) { + writeAttributeValueToXml( + out, TAG_DISABLE_CONTACTS_SEARCH, disableContactsSearch); + } + if (!disableBluetoothContactSharing) { + writeAttributeValueToXml( + out, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING, disableBluetoothContactSharing); + } + if (disableScreenCapture) { + writeAttributeValueToXml( + out, TAG_DISABLE_SCREEN_CAPTURE, disableScreenCapture); + } + if (requireAutoTime) { + writeAttributeValueToXml( + out, TAG_REQUIRE_AUTO_TIME, requireAutoTime); + } + if (forceEphemeralUsers) { + writeAttributeValueToXml( + out, TAG_FORCE_EPHEMERAL_USERS, forceEphemeralUsers); + } + if (isNetworkLoggingEnabled) { + out.startTag(null, TAG_IS_NETWORK_LOGGING_ENABLED); + out.attribute(null, ATTR_VALUE, Boolean.toString(isNetworkLoggingEnabled)); + out.attribute(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS, + Integer.toString(numNetworkLoggingNotifications)); + out.attribute(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION, + Long.toString(lastNetworkLoggingNotificationTimeMs)); + out.endTag(null, TAG_IS_NETWORK_LOGGING_ENABLED); + } + if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) { + writeAttributeValueToXml( + out, TAG_DISABLE_KEYGUARD_FEATURES, disabledKeyguardFeatures); + } + if (!accountTypesWithManagementDisabled.isEmpty()) { + writeAttributeValuesToXml( + out, TAG_DISABLE_ACCOUNT_MANAGEMENT, TAG_ACCOUNT_TYPE, + accountTypesWithManagementDisabled); + } + if (!trustAgentInfos.isEmpty()) { + Set<Map.Entry<String, TrustAgentInfo>> set = trustAgentInfos.entrySet(); + out.startTag(null, TAG_MANAGE_TRUST_AGENT_FEATURES); + for (Map.Entry<String, TrustAgentInfo> entry : set) { + TrustAgentInfo trustAgentInfo = entry.getValue(); + out.startTag(null, TAG_TRUST_AGENT_COMPONENT); + out.attribute(null, ATTR_VALUE, entry.getKey()); + if (trustAgentInfo.options != null) { + out.startTag(null, TAG_TRUST_AGENT_COMPONENT_OPTIONS); + try { + trustAgentInfo.options.saveToXml(out); + } catch (XmlPullParserException e) { + Log.e(DevicePolicyManagerService.LOG_TAG, + "Failed to save TrustAgent options", e); + } + out.endTag(null, TAG_TRUST_AGENT_COMPONENT_OPTIONS); + } + out.endTag(null, TAG_TRUST_AGENT_COMPONENT); + } + out.endTag(null, TAG_MANAGE_TRUST_AGENT_FEATURES); + } + if (crossProfileWidgetProviders != null && !crossProfileWidgetProviders.isEmpty()) { + writeAttributeValuesToXml( + out, TAG_CROSS_PROFILE_WIDGET_PROVIDERS, TAG_PROVIDER, + crossProfileWidgetProviders); + } + writePackageListToXml(out, TAG_PERMITTED_ACCESSIBILITY_SERVICES, + permittedAccessiblityServices); + writePackageListToXml(out, TAG_PERMITTED_IMES, permittedInputMethods); + writePackageListToXml(out, TAG_PERMITTED_NOTIFICATION_LISTENERS, + permittedNotificationListeners); + writePackageListToXml(out, TAG_KEEP_UNINSTALLED_PACKAGES, keepUninstalledPackages); + writePackageListToXml(out, TAG_METERED_DATA_DISABLED_PACKAGES, meteredDisabledPackages); + if (hasUserRestrictions()) { + UserRestrictionsUtils.writeRestrictions( + out, userRestrictions, TAG_USER_RESTRICTIONS); + } + if (!defaultEnabledRestrictionsAlreadySet.isEmpty()) { + writeAttributeValuesToXml(out, TAG_DEFAULT_ENABLED_USER_RESTRICTIONS, + TAG_RESTRICTION, + defaultEnabledRestrictionsAlreadySet); + } + if (!TextUtils.isEmpty(shortSupportMessage)) { + writeTextToXml(out, TAG_SHORT_SUPPORT_MESSAGE, shortSupportMessage.toString()); + } + if (!TextUtils.isEmpty(longSupportMessage)) { + writeTextToXml(out, TAG_LONG_SUPPORT_MESSAGE, longSupportMessage.toString()); + } + if (parentAdmin != null) { + out.startTag(null, TAG_PARENT_ADMIN); + parentAdmin.writeToXml(out); + out.endTag(null, TAG_PARENT_ADMIN); + } + if (organizationColor != DEF_ORGANIZATION_COLOR) { + writeAttributeValueToXml(out, TAG_ORGANIZATION_COLOR, organizationColor); + } + if (organizationName != null) { + writeTextToXml(out, TAG_ORGANIZATION_NAME, organizationName); + } + if (isLogoutEnabled) { + writeAttributeValueToXml(out, TAG_IS_LOGOUT_ENABLED, isLogoutEnabled); + } + if (startUserSessionMessage != null) { + writeTextToXml(out, TAG_START_USER_SESSION_MESSAGE, startUserSessionMessage); + } + if (endUserSessionMessage != null) { + writeTextToXml(out, TAG_END_USER_SESSION_MESSAGE, endUserSessionMessage); + } + if (mCrossProfileCalendarPackages == null) { + out.startTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL); + out.endTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL); + } else { + writePackageListToXml(out, TAG_CROSS_PROFILE_CALENDAR_PACKAGES, + mCrossProfileCalendarPackages); + } + writePackageListToXml(out, TAG_CROSS_PROFILE_PACKAGES, mCrossProfilePackages); + if (mFactoryResetProtectionPolicy != null) { + out.startTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); + mFactoryResetProtectionPolicy.writeToXml(out); + out.endTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); + } + if (mSuspendPersonalApps) { + writeAttributeValueToXml(out, TAG_SUSPEND_PERSONAL_APPS, mSuspendPersonalApps); + } + if (mProfileMaximumTimeOffMillis != 0) { + writeAttributeValueToXml(out, TAG_PROFILE_MAXIMUM_TIME_OFF, + mProfileMaximumTimeOffMillis); + } + if (mProfileMaximumTimeOffMillis != 0) { + writeAttributeValueToXml(out, TAG_PROFILE_OFF_DEADLINE, mProfileOffDeadline); + } + if (!TextUtils.isEmpty(mAlwaysOnVpnPackage)) { + writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_PACKAGE, mAlwaysOnVpnPackage); + } + if (mAlwaysOnVpnLockdown) { + writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_LOCKDOWN, mAlwaysOnVpnLockdown); + } + if (mCommonCriteriaMode) { + writeAttributeValueToXml(out, TAG_COMMON_CRITERIA_MODE, mCommonCriteriaMode); + } + } + + void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException { + out.startTag(null, tag); + out.text(text); + out.endTag(null, tag); + } + + void writePackageListToXml(XmlSerializer out, String outerTag, + List<String> packageList) + throws IllegalArgumentException, IllegalStateException, IOException { + if (packageList == null) { + return; + } + writeAttributeValuesToXml(out, outerTag, TAG_PACKAGE_LIST_ITEM, packageList); + } + + void writeAttributeValueToXml(XmlSerializer out, String tag, String value) + throws IOException { + out.startTag(null, tag); + out.attribute(null, ATTR_VALUE, value); + out.endTag(null, tag); + } + + void writeAttributeValueToXml(XmlSerializer out, String tag, int value) + throws IOException { + out.startTag(null, tag); + out.attribute(null, ATTR_VALUE, Integer.toString(value)); + out.endTag(null, tag); + } + + void writeAttributeValueToXml(XmlSerializer out, String tag, long value) + throws IOException { + out.startTag(null, tag); + out.attribute(null, ATTR_VALUE, Long.toString(value)); + out.endTag(null, tag); + } + + void writeAttributeValueToXml(XmlSerializer out, String tag, boolean value) + throws IOException { + out.startTag(null, tag); + out.attribute(null, ATTR_VALUE, Boolean.toString(value)); + out.endTag(null, tag); + } + + void writeAttributeValuesToXml(XmlSerializer out, String outerTag, String innerTag, + @NonNull Collection<String> values) throws IOException { + out.startTag(null, outerTag); + for (String value : values) { + out.startTag(null, innerTag); + out.attribute(null, ATTR_VALUE, value); + out.endTag(null, innerTag); + } + out.endTag(null, outerTag); + } + + void readFromXml(XmlPullParser parser, boolean shouldOverridePolicies) + throws XmlPullParserException, IOException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != END_DOCUMENT + && (type != END_TAG || parser.getDepth() > outerDepth)) { + if (type == END_TAG || type == TEXT) { + continue; + } + String tag = parser.getName(); + if (TAG_POLICIES.equals(tag)) { + if (shouldOverridePolicies) { + Log.d(DevicePolicyManagerService.LOG_TAG, + "Overriding device admin policies from XML."); + info.readPoliciesFromXml(parser); + } + } else if (TAG_PASSWORD_QUALITY.equals(tag)) { + mPasswordPolicy.quality = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) { + mPasswordPolicy.length = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) { + passwordHistoryLength = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) { + mPasswordPolicy.upperCase = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) { + mPasswordPolicy.lowerCase = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) { + mPasswordPolicy.letters = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) { + mPasswordPolicy.numeric = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) { + mPasswordPolicy.symbols = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) { + mPasswordPolicy.nonLetter = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) { + maximumTimeToUnlock = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_STRONG_AUTH_UNLOCK_TIMEOUT.equals(tag)) { + strongAuthUnlockTimeout = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) { + maximumFailedPasswordsForWipe = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_SPECIFIES_GLOBAL_PROXY.equals(tag)) { + specifiesGlobalProxy = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_GLOBAL_PROXY_SPEC.equals(tag)) { + globalProxySpec = + parser.getAttributeValue(null, ATTR_VALUE); + } else if (TAG_GLOBAL_PROXY_EXCLUSION_LIST.equals(tag)) { + globalProxyExclusionList = + parser.getAttributeValue(null, ATTR_VALUE); + } else if (TAG_PASSWORD_EXPIRATION_TIMEOUT.equals(tag)) { + passwordExpirationTimeout = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_PASSWORD_EXPIRATION_DATE.equals(tag)) { + passwordExpirationDate = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) { + encryptionRequested = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_TEST_ONLY_ADMIN.equals(tag)) { + testOnlyAdmin = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_CAMERA.equals(tag)) { + disableCamera = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_CALLER_ID.equals(tag)) { + disableCallerId = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_CONTACTS_SEARCH.equals(tag)) { + disableContactsSearch = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_BLUETOOTH_CONTACT_SHARING.equals(tag)) { + disableBluetoothContactSharing = Boolean.parseBoolean(parser + .getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_SCREEN_CAPTURE.equals(tag)) { + disableScreenCapture = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_REQUIRE_AUTO_TIME.equals(tag)) { + requireAutoTime = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_FORCE_EPHEMERAL_USERS.equals(tag)) { + forceEphemeralUsers = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_IS_NETWORK_LOGGING_ENABLED.equals(tag)) { + isNetworkLoggingEnabled = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + lastNetworkLoggingNotificationTimeMs = Long.parseLong( + parser.getAttributeValue(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION)); + numNetworkLoggingNotifications = Integer.parseInt( + parser.getAttributeValue(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS)); + } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) { + disabledKeyguardFeatures = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_ACCOUNT_MANAGEMENT.equals(tag)) { + readAttributeValues( + parser, TAG_ACCOUNT_TYPE, accountTypesWithManagementDisabled); + } else if (TAG_MANAGE_TRUST_AGENT_FEATURES.equals(tag)) { + trustAgentInfos = getAllTrustAgentInfos(parser, tag); + } else if (TAG_CROSS_PROFILE_WIDGET_PROVIDERS.equals(tag)) { + crossProfileWidgetProviders = new ArrayList<>(); + readAttributeValues(parser, TAG_PROVIDER, crossProfileWidgetProviders); + } else if (TAG_PERMITTED_ACCESSIBILITY_SERVICES.equals(tag)) { + permittedAccessiblityServices = readPackageList(parser, tag); + } else if (TAG_PERMITTED_IMES.equals(tag)) { + permittedInputMethods = readPackageList(parser, tag); + } else if (TAG_PERMITTED_NOTIFICATION_LISTENERS.equals(tag)) { + permittedNotificationListeners = readPackageList(parser, tag); + } else if (TAG_KEEP_UNINSTALLED_PACKAGES.equals(tag)) { + keepUninstalledPackages = readPackageList(parser, tag); + } else if (TAG_METERED_DATA_DISABLED_PACKAGES.equals(tag)) { + meteredDisabledPackages = readPackageList(parser, tag); + } else if (TAG_USER_RESTRICTIONS.equals(tag)) { + userRestrictions = UserRestrictionsUtils.readRestrictions(parser); + } else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) { + readAttributeValues( + parser, TAG_RESTRICTION, defaultEnabledRestrictionsAlreadySet); + } else if (TAG_SHORT_SUPPORT_MESSAGE.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + shortSupportMessage = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing text when loading short support message"); + } + } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + longSupportMessage = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing text when loading long support message"); + } + } else if (TAG_PARENT_ADMIN.equals(tag)) { + Preconditions.checkState(!isParent); + parentAdmin = new ActiveAdmin(info, /* parent */ true); + parentAdmin.readFromXml(parser, shouldOverridePolicies); + } else if (TAG_ORGANIZATION_COLOR.equals(tag)) { + organizationColor = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_ORGANIZATION_NAME.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + organizationName = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing text when loading organization name"); + } + } else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) { + isLogoutEnabled = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_START_USER_SESSION_MESSAGE.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + startUserSessionMessage = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing text when loading start session message"); + } + } else if (TAG_END_USER_SESSION_MESSAGE.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + endUserSessionMessage = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing text when loading end session message"); + } + } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES.equals(tag)) { + mCrossProfileCalendarPackages = readPackageList(parser, tag); + } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL.equals(tag)) { + mCrossProfileCalendarPackages = null; + } else if (TAG_CROSS_PROFILE_PACKAGES.equals(tag)) { + mCrossProfilePackages = readPackageList(parser, tag); + } else if (TAG_FACTORY_RESET_PROTECTION_POLICY.equals(tag)) { + mFactoryResetProtectionPolicy = FactoryResetProtectionPolicy.readFromXml( + parser); + } else if (TAG_SUSPEND_PERSONAL_APPS.equals(tag)) { + mSuspendPersonalApps = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_PROFILE_MAXIMUM_TIME_OFF.equals(tag)) { + mProfileMaximumTimeOffMillis = + Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) { + mProfileOffDeadline = + Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_ALWAYS_ON_VPN_PACKAGE.equals(tag)) { + mAlwaysOnVpnPackage = parser.getAttributeValue(null, ATTR_VALUE); + } else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) { + mAlwaysOnVpnLockdown = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_COMMON_CRITERIA_MODE.equals(tag)) { + mCommonCriteriaMode = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown admin tag: " + tag); + XmlUtils.skipCurrentTag(parser); + } + } + } + + private List<String> readPackageList(XmlPullParser parser, + String tag) throws XmlPullParserException, IOException { + List<String> result = new ArrayList<String>(); + int outerDepth = parser.getDepth(); + int outerType; + while ((outerType = parser.next()) != XmlPullParser.END_DOCUMENT + && (outerType != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (outerType == XmlPullParser.END_TAG || outerType == XmlPullParser.TEXT) { + continue; + } + String outerTag = parser.getName(); + if (TAG_PACKAGE_LIST_ITEM.equals(outerTag)) { + String packageName = parser.getAttributeValue(null, ATTR_VALUE); + if (packageName != null) { + result.add(packageName); + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, + "Package name missing under " + outerTag); + } + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, + "Unknown tag under " + tag + ": " + outerTag); + } + } + return result; + } + + private void readAttributeValues( + XmlPullParser parser, String tag, Collection<String> result) + throws XmlPullParserException, IOException { + result.clear(); + int outerDepthDAM = parser.getDepth(); + int typeDAM; + while ((typeDAM = parser.next()) != END_DOCUMENT + && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { + if (typeDAM == END_TAG || typeDAM == TEXT) { + continue; + } + String tagDAM = parser.getName(); + if (tag.equals(tagDAM)) { + result.add(parser.getAttributeValue(null, ATTR_VALUE)); + } else { + Slog.e(DevicePolicyManagerService.LOG_TAG, + "Expected tag " + tag + " but found " + tagDAM); + } + } + } + + @NonNull + private ArrayMap<String, TrustAgentInfo> getAllTrustAgentInfos( + XmlPullParser parser, String tag) throws XmlPullParserException, IOException { + int outerDepthDAM = parser.getDepth(); + int typeDAM; + final ArrayMap<String, TrustAgentInfo> result = new ArrayMap<>(); + while ((typeDAM = parser.next()) != END_DOCUMENT + && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { + if (typeDAM == END_TAG || typeDAM == TEXT) { + continue; + } + String tagDAM = parser.getName(); + if (TAG_TRUST_AGENT_COMPONENT.equals(tagDAM)) { + final String component = parser.getAttributeValue(null, ATTR_VALUE); + final TrustAgentInfo trustAgentInfo = getTrustAgentInfo(parser, tag); + result.put(component, trustAgentInfo); + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, + "Unknown tag under " + tag + ": " + tagDAM); + } + } + return result; + } + + private TrustAgentInfo getTrustAgentInfo(XmlPullParser parser, String tag) + throws XmlPullParserException, IOException { + int outerDepthDAM = parser.getDepth(); + int typeDAM; + TrustAgentInfo result = new TrustAgentInfo(null); + while ((typeDAM = parser.next()) != END_DOCUMENT + && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { + if (typeDAM == END_TAG || typeDAM == TEXT) { + continue; + } + String tagDAM = parser.getName(); + if (TAG_TRUST_AGENT_COMPONENT_OPTIONS.equals(tagDAM)) { + result.options = PersistableBundle.restoreFromXml(parser); + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, + "Unknown tag under " + tag + ": " + tagDAM); + } + } + return result; + } + + boolean hasUserRestrictions() { + return userRestrictions != null && userRestrictions.size() > 0; + } + + Bundle ensureUserRestrictions() { + if (userRestrictions == null) { + userRestrictions = new Bundle(); + } + return userRestrictions; + } + + public void transfer(DeviceAdminInfo deviceAdminInfo) { + if (hasParentActiveAdmin()) { + parentAdmin.info = deviceAdminInfo; + } + info = deviceAdminInfo; + } + + Bundle addSyntheticRestrictions(Bundle restrictions) { + if (disableCamera) { + restrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); + } + if (requireAutoTime) { + restrictions.putBoolean(UserManager.DISALLOW_CONFIG_DATE_TIME, true); + } + return restrictions; + } + + static Bundle removeDeprecatedRestrictions(Bundle restrictions) { + for (String deprecatedRestriction: UserRestrictionsUtils.DEPRECATED_USER_RESTRICTIONS) { + restrictions.remove(deprecatedRestriction); + } + return restrictions; + } + + static Bundle filterRestrictions(Bundle restrictions, Predicate<String> filter) { + Bundle result = new Bundle(); + for (String key : restrictions.keySet()) { + if (!restrictions.getBoolean(key)) { + continue; + } + if (filter.test(key)) { + result.putBoolean(key, true); + } + } + return result; + } + + Bundle getEffectiveRestrictions() { + return addSyntheticRestrictions( + removeDeprecatedRestrictions(new Bundle(ensureUserRestrictions()))); + } + + Bundle getLocalUserRestrictions(int adminType) { + return filterRestrictions(getEffectiveRestrictions(), + key -> UserRestrictionsUtils.isLocal(adminType, key)); + } + + Bundle getGlobalUserRestrictions(int adminType) { + return filterRestrictions(getEffectiveRestrictions(), + key -> UserRestrictionsUtils.isGlobal(adminType, key)); + } + + void dump(IndentingPrintWriter pw) { + pw.print("uid="); + pw.println(getUid()); + + pw.print("testOnlyAdmin="); + pw.println(testOnlyAdmin); + + pw.println("policies:"); + ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies(); + if (pols != null) { + pw.increaseIndent(); + for (int i = 0; i < pols.size(); i++) { + pw.println(pols.get(i).tag); + } + pw.decreaseIndent(); + } + + pw.print("passwordQuality=0x"); + pw.println(Integer.toHexString(mPasswordPolicy.quality)); + + pw.print("minimumPasswordLength="); + pw.println(mPasswordPolicy.length); + + pw.print("passwordHistoryLength="); + pw.println(passwordHistoryLength); + + pw.print("minimumPasswordUpperCase="); + pw.println(mPasswordPolicy.upperCase); + + pw.print("minimumPasswordLowerCase="); + pw.println(mPasswordPolicy.lowerCase); + + pw.print("minimumPasswordLetters="); + pw.println(mPasswordPolicy.letters); + + pw.print("minimumPasswordNumeric="); + pw.println(mPasswordPolicy.numeric); + + pw.print("minimumPasswordSymbols="); + pw.println(mPasswordPolicy.symbols); + + pw.print("minimumPasswordNonLetter="); + pw.println(mPasswordPolicy.nonLetter); + + pw.print("maximumTimeToUnlock="); + pw.println(maximumTimeToUnlock); + + pw.print("strongAuthUnlockTimeout="); + pw.println(strongAuthUnlockTimeout); + + pw.print("maximumFailedPasswordsForWipe="); + pw.println(maximumFailedPasswordsForWipe); + + pw.print("specifiesGlobalProxy="); + pw.println(specifiesGlobalProxy); + + pw.print("passwordExpirationTimeout="); + pw.println(passwordExpirationTimeout); + + pw.print("passwordExpirationDate="); + pw.println(passwordExpirationDate); + + if (globalProxySpec != null) { + pw.print("globalProxySpec="); + pw.println(globalProxySpec); + } + if (globalProxyExclusionList != null) { + pw.print("globalProxyEclusionList="); + pw.println(globalProxyExclusionList); + } + pw.print("encryptionRequested="); + pw.println(encryptionRequested); + + pw.print("disableCamera="); + pw.println(disableCamera); + + pw.print("disableCallerId="); + pw.println(disableCallerId); + + pw.print("disableContactsSearch="); + pw.println(disableContactsSearch); + + pw.print("disableBluetoothContactSharing="); + pw.println(disableBluetoothContactSharing); + + pw.print("disableScreenCapture="); + pw.println(disableScreenCapture); + + pw.print("requireAutoTime="); + pw.println(requireAutoTime); + + pw.print("forceEphemeralUsers="); + pw.println(forceEphemeralUsers); + + pw.print("isNetworkLoggingEnabled="); + pw.println(isNetworkLoggingEnabled); + + pw.print("disabledKeyguardFeatures="); + pw.println(disabledKeyguardFeatures); + + pw.print("crossProfileWidgetProviders="); + pw.println(crossProfileWidgetProviders); + + if (permittedAccessiblityServices != null) { + pw.print("permittedAccessibilityServices="); + pw.println(permittedAccessiblityServices); + } + + if (permittedInputMethods != null) { + pw.print("permittedInputMethods="); + pw.println(permittedInputMethods); + } + + if (permittedNotificationListeners != null) { + pw.print("permittedNotificationListeners="); + pw.println(permittedNotificationListeners); + } + + if (keepUninstalledPackages != null) { + pw.print("keepUninstalledPackages="); + pw.println(keepUninstalledPackages); + } + + pw.print("organizationColor="); + pw.println(organizationColor); + + if (organizationName != null) { + pw.print("organizationName="); + pw.println(organizationName); + } + + pw.println("userRestrictions:"); + UserRestrictionsUtils.dumpRestrictions(pw, " ", userRestrictions); + + pw.print("defaultEnabledRestrictionsAlreadySet="); + pw.println(defaultEnabledRestrictionsAlreadySet); + + pw.print("isParent="); + pw.println(isParent); + + if (parentAdmin != null) { + pw.println("parentAdmin:"); + pw.increaseIndent(); + parentAdmin.dump(pw); + pw.decreaseIndent(); + } + + if (mCrossProfileCalendarPackages != null) { + pw.print("mCrossProfileCalendarPackages="); + pw.println(mCrossProfileCalendarPackages); + } + + pw.print("mCrossProfilePackages="); + pw.println(mCrossProfilePackages); + + pw.print("mSuspendPersonalApps="); + pw.println(mSuspendPersonalApps); + + pw.print("mProfileMaximumTimeOffMillis="); + pw.println(mProfileMaximumTimeOffMillis); + + pw.print("mProfileOffDeadline="); + pw.println(mProfileOffDeadline); + + pw.print("mAlwaysOnVpnPackage="); + pw.println(mAlwaysOnVpnPackage); + + pw.print("mAlwaysOnVpnLockdown="); + pw.println(mAlwaysOnVpnLockdown); + + pw.print("mCommonCriteriaMode="); + pw.println(mCommonCriteriaMode); + } +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java new file mode 100644 index 000000000000..130cfd50b203 --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2020 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.devicepolicy; + +import android.app.admin.DeviceAdminInfo; +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; +import android.os.FileUtils; +import android.os.PersistableBundle; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Slog; +import android.util.Xml; + +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.JournaledFile; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +class DevicePolicyData { + private static final String TAG_ACCEPTED_CA_CERTIFICATES = "accepted-ca-certificate"; + private static final String TAG_LOCK_TASK_COMPONENTS = "lock-task-component"; + private static final String TAG_LOCK_TASK_FEATURES = "lock-task-features"; + private static final String TAG_STATUS_BAR = "statusbar"; + private static final String TAG_APPS_SUSPENDED = "apps-suspended"; + private static final String TAG_SECONDARY_LOCK_SCREEN = "secondary-lock-screen"; + private static final String TAG_DO_NOT_ASK_CREDENTIALS_ON_BOOT = + "do-not-ask-credentials-on-boot"; + private static final String TAG_AFFILIATION_ID = "affiliation-id"; + private static final String TAG_LAST_SECURITY_LOG_RETRIEVAL = "last-security-log-retrieval"; + private static final String TAG_LAST_BUG_REPORT_REQUEST = "last-bug-report-request"; + private static final String TAG_LAST_NETWORK_LOG_RETRIEVAL = "last-network-log-retrieval"; + private static final String TAG_ADMIN_BROADCAST_PENDING = "admin-broadcast-pending"; + private static final String TAG_CURRENT_INPUT_METHOD_SET = "current-ime-set"; + private static final String TAG_OWNER_INSTALLED_CA_CERT = "owner-installed-ca-cert"; + private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle"; + private static final String TAG_PASSWORD_VALIDITY = "password-validity"; + private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token"; + private static final String TAG_PROTECTED_PACKAGES = "protected-packages"; + private static final String ATTR_VALUE = "value"; + private static final String ATTR_ALIAS = "alias"; + private static final String ATTR_ID = "id"; + private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; + private static final String ATTR_NAME = "name"; + private static final String ATTR_DISABLED = "disabled"; + private static final String ATTR_SETUP_COMPLETE = "setup-complete"; + private static final String ATTR_PROVISIONING_STATE = "provisioning-state"; + private static final String ATTR_PERMISSION_POLICY = "permission-policy"; + private static final String ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED = + "device-provisioning-config-applied"; + private static final String ATTR_DEVICE_PAIRED = "device-paired"; + + int mFailedPasswordAttempts = 0; + boolean mPasswordValidAtLastCheckpoint = true; + + int mUserHandle; + int mPasswordOwner = -1; + long mLastMaximumTimeToLock = -1; + boolean mUserSetupComplete = false; + boolean mPaired = false; + int mUserProvisioningState; + int mPermissionPolicy; + + boolean mDeviceProvisioningConfigApplied = false; + + final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>(); + final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>(); + final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>(); + + // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead. + final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>(); + + // This is the list of component allowed to start lock task mode. + List<String> mLockTaskPackages = new ArrayList<>(); + + // List of packages protected by device owner + List<String> mUserControlDisabledPackages = new ArrayList<>(); + + // Bitfield of feature flags to be enabled during LockTask mode. + // We default on the power button menu, in order to be consistent with pre-P behaviour. + int mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS; + + boolean mStatusBarDisabled = false; + + ComponentName mRestrictionsProvider; + + // Map of delegate package to delegation scopes + final ArrayMap<String, List<String>> mDelegationMap = new ArrayMap<>(); + + boolean mDoNotAskCredentialsOnBoot = false; + + Set<String> mAffiliationIds = new ArraySet<>(); + + long mLastSecurityLogRetrievalTime = -1; + + long mLastBugReportRequestTime = -1; + + long mLastNetworkLogsRetrievalTime = -1; + + boolean mCurrentInputMethodSet = false; + + boolean mSecondaryLockscreenEnabled = false; + + // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead. + Set<String> mOwnerInstalledCaCerts = new ArraySet<>(); + + // Used for initialization of users created by createAndManageUser. + boolean mAdminBroadcastPending = false; + PersistableBundle mInitBundle = null; + + long mPasswordTokenHandle = 0; + + // Whether user's apps are suspended. This flag should only be written AFTER all the needed + // apps were suspended or unsuspended. + boolean mAppsSuspended = false; + + DevicePolicyData(int userHandle) { + mUserHandle = userHandle; + } + + /** + * Serializes DevicePolicyData object as XML. + */ + static boolean store(DevicePolicyData policyData, JournaledFile file, boolean isFdeDevice) { + FileOutputStream stream = null; + try { + stream = new FileOutputStream(file.chooseForWrite(), false); + XmlSerializer out = new FastXmlSerializer(); + out.setOutput(stream, StandardCharsets.UTF_8.name()); + out.startDocument(null, true); + + out.startTag(null, "policies"); + if (policyData.mRestrictionsProvider != null) { + out.attribute(null, ATTR_PERMISSION_PROVIDER, + policyData.mRestrictionsProvider.flattenToString()); + } + if (policyData.mUserSetupComplete) { + out.attribute(null, ATTR_SETUP_COMPLETE, + Boolean.toString(true)); + } + if (policyData.mPaired) { + out.attribute(null, ATTR_DEVICE_PAIRED, + Boolean.toString(true)); + } + if (policyData.mDeviceProvisioningConfigApplied) { + out.attribute(null, ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED, + Boolean.toString(true)); + } + if (policyData.mUserProvisioningState != DevicePolicyManager.STATE_USER_UNMANAGED) { + out.attribute(null, ATTR_PROVISIONING_STATE, + Integer.toString(policyData.mUserProvisioningState)); + } + if (policyData.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) { + out.attribute(null, ATTR_PERMISSION_POLICY, + Integer.toString(policyData.mPermissionPolicy)); + } + + // Serialize delegations. + for (int i = 0; i < policyData.mDelegationMap.size(); ++i) { + final String delegatePackage = policyData.mDelegationMap.keyAt(i); + final List<String> scopes = policyData.mDelegationMap.valueAt(i); + + // Every "delegation" tag serializes the information of one delegate-scope pair. + for (String scope : scopes) { + out.startTag(null, "delegation"); + out.attribute(null, "delegatePackage", delegatePackage); + out.attribute(null, "scope", scope); + out.endTag(null, "delegation"); + } + } + + final int n = policyData.mAdminList.size(); + for (int i = 0; i < n; i++) { + ActiveAdmin ap = policyData.mAdminList.get(i); + if (ap != null) { + out.startTag(null, "admin"); + out.attribute(null, "name", ap.info.getComponent().flattenToString()); + ap.writeToXml(out); + out.endTag(null, "admin"); + } + } + + if (policyData.mPasswordOwner >= 0) { + out.startTag(null, "password-owner"); + out.attribute(null, "value", Integer.toString(policyData.mPasswordOwner)); + out.endTag(null, "password-owner"); + } + + if (policyData.mFailedPasswordAttempts != 0) { + out.startTag(null, "failed-password-attempts"); + out.attribute(null, "value", Integer.toString(policyData.mFailedPasswordAttempts)); + out.endTag(null, "failed-password-attempts"); + } + + // For FDE devices only, we save this flag so we can report on password sufficiency + // before the user enters their password for the first time after a reboot. For + // security reasons, we don't want to store the full set of active password metrics. + if (isFdeDevice) { + out.startTag(null, TAG_PASSWORD_VALIDITY); + out.attribute(null, ATTR_VALUE, + Boolean.toString(policyData.mPasswordValidAtLastCheckpoint)); + out.endTag(null, TAG_PASSWORD_VALIDITY); + } + + for (int i = 0; i < policyData.mAcceptedCaCertificates.size(); i++) { + out.startTag(null, TAG_ACCEPTED_CA_CERTIFICATES); + out.attribute(null, ATTR_NAME, policyData.mAcceptedCaCertificates.valueAt(i)); + out.endTag(null, TAG_ACCEPTED_CA_CERTIFICATES); + } + + for (int i = 0; i < policyData.mLockTaskPackages.size(); i++) { + String component = policyData.mLockTaskPackages.get(i); + out.startTag(null, TAG_LOCK_TASK_COMPONENTS); + out.attribute(null, "name", component); + out.endTag(null, TAG_LOCK_TASK_COMPONENTS); + } + + if (policyData.mLockTaskFeatures != DevicePolicyManager.LOCK_TASK_FEATURE_NONE) { + out.startTag(null, TAG_LOCK_TASK_FEATURES); + out.attribute(null, ATTR_VALUE, Integer.toString(policyData.mLockTaskFeatures)); + out.endTag(null, TAG_LOCK_TASK_FEATURES); + } + + if (policyData.mSecondaryLockscreenEnabled) { + out.startTag(null, TAG_SECONDARY_LOCK_SCREEN); + out.attribute(null, ATTR_VALUE, Boolean.toString(true)); + out.endTag(null, TAG_SECONDARY_LOCK_SCREEN); + } + + if (policyData.mStatusBarDisabled) { + out.startTag(null, TAG_STATUS_BAR); + out.attribute(null, ATTR_DISABLED, Boolean.toString(policyData.mStatusBarDisabled)); + out.endTag(null, TAG_STATUS_BAR); + } + + if (policyData.mDoNotAskCredentialsOnBoot) { + out.startTag(null, TAG_DO_NOT_ASK_CREDENTIALS_ON_BOOT); + out.endTag(null, TAG_DO_NOT_ASK_CREDENTIALS_ON_BOOT); + } + + for (String id : policyData.mAffiliationIds) { + out.startTag(null, TAG_AFFILIATION_ID); + out.attribute(null, ATTR_ID, id); + out.endTag(null, TAG_AFFILIATION_ID); + } + + if (policyData.mLastSecurityLogRetrievalTime >= 0) { + out.startTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL); + out.attribute(null, ATTR_VALUE, + Long.toString(policyData.mLastSecurityLogRetrievalTime)); + out.endTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL); + } + + if (policyData.mLastBugReportRequestTime >= 0) { + out.startTag(null, TAG_LAST_BUG_REPORT_REQUEST); + out.attribute(null, ATTR_VALUE, + Long.toString(policyData.mLastBugReportRequestTime)); + out.endTag(null, TAG_LAST_BUG_REPORT_REQUEST); + } + + if (policyData.mLastNetworkLogsRetrievalTime >= 0) { + out.startTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL); + out.attribute(null, ATTR_VALUE, + Long.toString(policyData.mLastNetworkLogsRetrievalTime)); + out.endTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL); + } + + if (policyData.mAdminBroadcastPending) { + out.startTag(null, TAG_ADMIN_BROADCAST_PENDING); + out.attribute(null, ATTR_VALUE, + Boolean.toString(policyData.mAdminBroadcastPending)); + out.endTag(null, TAG_ADMIN_BROADCAST_PENDING); + } + + if (policyData.mInitBundle != null) { + out.startTag(null, TAG_INITIALIZATION_BUNDLE); + policyData.mInitBundle.saveToXml(out); + out.endTag(null, TAG_INITIALIZATION_BUNDLE); + } + + if (policyData.mPasswordTokenHandle != 0) { + out.startTag(null, TAG_PASSWORD_TOKEN_HANDLE); + out.attribute(null, ATTR_VALUE, + Long.toString(policyData.mPasswordTokenHandle)); + out.endTag(null, TAG_PASSWORD_TOKEN_HANDLE); + } + + if (policyData.mCurrentInputMethodSet) { + out.startTag(null, TAG_CURRENT_INPUT_METHOD_SET); + out.endTag(null, TAG_CURRENT_INPUT_METHOD_SET); + } + + for (final String cert : policyData.mOwnerInstalledCaCerts) { + out.startTag(null, TAG_OWNER_INSTALLED_CA_CERT); + out.attribute(null, ATTR_ALIAS, cert); + out.endTag(null, TAG_OWNER_INSTALLED_CA_CERT); + } + + for (int i = 0, size = policyData.mUserControlDisabledPackages.size(); i < size; i++) { + String packageName = policyData.mUserControlDisabledPackages.get(i); + out.startTag(null, TAG_PROTECTED_PACKAGES); + out.attribute(null, ATTR_NAME, packageName); + out.endTag(null, TAG_PROTECTED_PACKAGES); + } + + if (policyData.mAppsSuspended) { + out.startTag(null, TAG_APPS_SUSPENDED); + out.attribute(null, ATTR_VALUE, Boolean.toString(policyData.mAppsSuspended)); + out.endTag(null, TAG_APPS_SUSPENDED); + } + + out.endTag(null, "policies"); + + out.endDocument(); + stream.flush(); + FileUtils.sync(stream); + stream.close(); + file.commit(); + return true; + } catch (XmlPullParserException | IOException e) { + Slog.w(DevicePolicyManagerService.LOG_TAG, "failed writing file", e); + try { + if (stream != null) { + stream.close(); + } + } catch (IOException ex) { + // Ignore + } + file.rollback(); + return false; + } + } + + /** + * @param adminInfoSupplier function that queries DeviceAdminInfo from PackageManager + * @param ownerComponent device or profile owner component if any. + */ + static boolean load(DevicePolicyData policy, boolean isFdeDevice, JournaledFile journaledFile, + Function<ComponentName, DeviceAdminInfo> adminInfoSupplier, + ComponentName ownerComponent) { + FileInputStream stream = null; + File file = journaledFile.chooseForRead(); + boolean needsRewrite = false; + try { + stream = new FileInputStream(file); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(stream, StandardCharsets.UTF_8.name()); + + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && type != XmlPullParser.START_TAG) { + } + String tag = parser.getName(); + if (!"policies".equals(tag)) { + throw new XmlPullParserException( + "Settings do not start with policies tag: found " + tag); + } + + // Extract the permission provider component name if available + String permissionProvider = parser.getAttributeValue(null, ATTR_PERMISSION_PROVIDER); + if (permissionProvider != null) { + policy.mRestrictionsProvider = + ComponentName.unflattenFromString(permissionProvider); + } + String userSetupComplete = parser.getAttributeValue(null, ATTR_SETUP_COMPLETE); + if (Boolean.toString(true).equals(userSetupComplete)) { + policy.mUserSetupComplete = true; + } + String paired = parser.getAttributeValue(null, ATTR_DEVICE_PAIRED); + if (Boolean.toString(true).equals(paired)) { + policy.mPaired = true; + } + String deviceProvisioningConfigApplied = parser.getAttributeValue(null, + ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED); + if (Boolean.toString(true).equals(deviceProvisioningConfigApplied)) { + policy.mDeviceProvisioningConfigApplied = true; + } + String provisioningState = parser.getAttributeValue(null, ATTR_PROVISIONING_STATE); + if (!TextUtils.isEmpty(provisioningState)) { + policy.mUserProvisioningState = Integer.parseInt(provisioningState); + } + String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY); + if (!TextUtils.isEmpty(permissionPolicy)) { + policy.mPermissionPolicy = Integer.parseInt(permissionPolicy); + } + + parser.next(); + int outerDepth = parser.getDepth(); + policy.mLockTaskPackages.clear(); + policy.mAdminList.clear(); + policy.mAdminMap.clear(); + policy.mAffiliationIds.clear(); + policy.mOwnerInstalledCaCerts.clear(); + policy.mUserControlDisabledPackages.clear(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + tag = parser.getName(); + if ("admin".equals(tag)) { + String name = parser.getAttributeValue(null, "name"); + try { + DeviceAdminInfo dai = adminInfoSupplier.apply( + ComponentName.unflattenFromString(name)); + + if (dai != null) { + // b/123415062: If DA, overwrite with the stored policies that were + // agreed by the user to prevent apps from sneaking additional policies + // into updates. + boolean overwritePolicies = !dai.getComponent().equals(ownerComponent); + ActiveAdmin ap = new ActiveAdmin(dai, /* parent */ false); + ap.readFromXml(parser, overwritePolicies); + policy.mAdminMap.put(ap.info.getComponent(), ap); + } + } catch (RuntimeException e) { + Slog.w(DevicePolicyManagerService.LOG_TAG, + "Failed loading admin " + name, e); + } + } else if ("delegation".equals(tag)) { + // Parse delegation info. + final String delegatePackage = parser.getAttributeValue(null, + "delegatePackage"); + final String scope = parser.getAttributeValue(null, "scope"); + + // Get a reference to the scopes list for the delegatePackage. + List<String> scopes = policy.mDelegationMap.get(delegatePackage); + // Or make a new list if none was found. + if (scopes == null) { + scopes = new ArrayList<>(); + policy.mDelegationMap.put(delegatePackage, scopes); + } + // Add the new scope to the list of delegatePackage if it's not already there. + if (!scopes.contains(scope)) { + scopes.add(scope); + } + } else if ("failed-password-attempts".equals(tag)) { + policy.mFailedPasswordAttempts = Integer.parseInt( + parser.getAttributeValue(null, "value")); + } else if ("password-owner".equals(tag)) { + policy.mPasswordOwner = Integer.parseInt( + parser.getAttributeValue(null, "value")); + } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) { + policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME)); + } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { + policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name")); + } else if (TAG_LOCK_TASK_FEATURES.equals(tag)) { + policy.mLockTaskFeatures = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_SECONDARY_LOCK_SCREEN.equals(tag)) { + policy.mSecondaryLockscreenEnabled = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_STATUS_BAR.equals(tag)) { + policy.mStatusBarDisabled = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_DISABLED)); + } else if (TAG_DO_NOT_ASK_CREDENTIALS_ON_BOOT.equals(tag)) { + policy.mDoNotAskCredentialsOnBoot = true; + } else if (TAG_AFFILIATION_ID.equals(tag)) { + policy.mAffiliationIds.add(parser.getAttributeValue(null, ATTR_ID)); + } else if (TAG_LAST_SECURITY_LOG_RETRIEVAL.equals(tag)) { + policy.mLastSecurityLogRetrievalTime = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_LAST_BUG_REPORT_REQUEST.equals(tag)) { + policy.mLastBugReportRequestTime = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_LAST_NETWORK_LOG_RETRIEVAL.equals(tag)) { + policy.mLastNetworkLogsRetrievalTime = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) { + String pending = parser.getAttributeValue(null, ATTR_VALUE); + policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); + } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) { + policy.mInitBundle = PersistableBundle.restoreFromXml(parser); + } else if ("active-password".equals(tag)) { + // Remove password metrics from saved settings, as we no longer wish to store + // these on disk + needsRewrite = true; + } else if (TAG_PASSWORD_VALIDITY.equals(tag)) { + if (isFdeDevice) { + // This flag is only used for FDE devices + policy.mPasswordValidAtLastCheckpoint = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } + } else if (TAG_PASSWORD_TOKEN_HANDLE.equals(tag)) { + policy.mPasswordTokenHandle = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_CURRENT_INPUT_METHOD_SET.equals(tag)) { + policy.mCurrentInputMethodSet = true; + } else if (TAG_OWNER_INSTALLED_CA_CERT.equals(tag)) { + policy.mOwnerInstalledCaCerts.add(parser.getAttributeValue(null, ATTR_ALIAS)); + } else if (TAG_PROTECTED_PACKAGES.equals(tag)) { + policy.mUserControlDisabledPackages.add( + parser.getAttributeValue(null, ATTR_NAME)); + } else if (TAG_APPS_SUSPENDED.equals(tag)) { + policy.mAppsSuspended = + Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_VALUE)); + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown tag: " + tag); + XmlUtils.skipCurrentTag(parser); + } + } + } catch (FileNotFoundException e) { + // Don't be noisy, this is normal if we haven't defined any policies. + } catch (NullPointerException | NumberFormatException | XmlPullParserException | IOException + | IndexOutOfBoundsException e) { + Slog.w(DevicePolicyManagerService.LOG_TAG, "failed parsing " + file, e); + } + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + // Ignore + } + + // Generate a list of admins from the admin map + policy.mAdminList.addAll(policy.mAdminMap.values()); + return needsRewrite; + } + + void validatePasswordOwner() { + if (mPasswordOwner >= 0) { + boolean haveOwner = false; + for (int i = mAdminList.size() - 1; i >= 0; i--) { + if (mAdminList.get(i).getUid() == mPasswordOwner) { + haveOwner = true; + break; + } + } + if (!haveOwner) { + Slog.w(DevicePolicyManagerService.LOG_TAG, "Previous password owner " + + mPasswordOwner + " no longer active; disabling"); + mPasswordOwner = -1; + } + } + } +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 9a2bef85860f..cafd56e5198b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -106,10 +106,6 @@ import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.A import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; -import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; -import static org.xmlpull.v1.XmlPullParser.END_TAG; -import static org.xmlpull.v1.XmlPullParser.TEXT; - import android.Manifest.permission; import android.accessibilityservice.AccessibilityServiceInfo; import android.accounts.Account; @@ -189,7 +185,6 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.database.Cursor; import android.graphics.Bitmap; -import android.graphics.Color; import android.location.LocationManager; import android.media.AudioManager; import android.media.IAudioService; @@ -204,7 +199,6 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Environment; -import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -248,7 +242,6 @@ import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.text.TextUtils; import android.text.format.DateUtils; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Log; @@ -280,7 +273,6 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.JournaledFile; import com.android.internal.util.Preconditions; import com.android.internal.util.StatLogger; -import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockSettingsInternal; import com.android.internal.widget.LockscreenCredential; @@ -290,8 +282,7 @@ import com.android.server.LockGuard; import com.android.server.PersistentDataBlockManagerInternal; import com.android.server.SystemServerInitThreadPool; import com.android.server.SystemService; -import com.android.server.SystemService.TargetUser; -import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo; +import com.android.server.devicepolicy.ActiveAdmin.TrustAgentInfo; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.pm.RestrictionsSet; @@ -328,7 +319,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -350,55 +340,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final String TRANSFER_OWNERSHIP_PARAMETERS_XML = "transfer-ownership-parameters.xml"; - private static final String TAG_ACCEPTED_CA_CERTIFICATES = "accepted-ca-certificate"; - - private static final String TAG_LOCK_TASK_COMPONENTS = "lock-task-component"; - - private static final String TAG_LOCK_TASK_FEATURES = "lock-task-features"; - - private static final String TAG_STATUS_BAR = "statusbar"; - - private static final String ATTR_DISABLED = "disabled"; - - private static final String ATTR_NAME = "name"; - - private static final String DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML = - "do-not-ask-credentials-on-boot"; - - private static final String TAG_AFFILIATION_ID = "affiliation-id"; - - private static final String TAG_LAST_SECURITY_LOG_RETRIEVAL = "last-security-log-retrieval"; - - private static final String TAG_LAST_BUG_REPORT_REQUEST = "last-bug-report-request"; - - private static final String TAG_LAST_NETWORK_LOG_RETRIEVAL = "last-network-log-retrieval"; - - private static final String TAG_ADMIN_BROADCAST_PENDING = "admin-broadcast-pending"; - - private static final String TAG_CURRENT_INPUT_METHOD_SET = "current-ime-set"; - - private static final String TAG_OWNER_INSTALLED_CA_CERT = "owner-installed-ca-cert"; - - private static final String ATTR_ID = "id"; - - private static final String ATTR_VALUE = "value"; - - private static final String ATTR_ALIAS = "alias"; - - private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle"; - - private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token"; - - private static final String TAG_PASSWORD_VALIDITY = "password-validity"; - private static final String TAG_TRANSFER_OWNERSHIP_BUNDLE = "transfer-ownership-bundle"; - private static final String TAG_PROTECTED_PACKAGES = "protected-packages"; - - private static final String TAG_SECONDARY_LOCK_SCREEN = "secondary-lock-screen"; - - private static final String TAG_APPS_SUSPENDED = "apps-suspended"; - private static final int REQUEST_EXPIRE_PASSWORD = 5571; private static final int REQUEST_PROFILE_OFF_DEADLINE = 5572; @@ -423,17 +366,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { static final String ACTION_PROFILE_OFF_DEADLINE = "com.android.server.ACTION_PROFILE_OFF_DEADLINE"; - private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; - private static final String ATTR_SETUP_COMPLETE = "setup-complete"; - private static final String ATTR_PROVISIONING_STATE = "provisioning-state"; - private static final String ATTR_PERMISSION_POLICY = "permission-policy"; - private static final String ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED = - "device-provisioning-config-applied"; - private static final String ATTR_DEVICE_PAIRED = "device-paired"; - private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer"; - private static final String ATTR_APPLICATION_RESTRICTIONS_MANAGER - = "application-restrictions-manager"; - private static final String CALLED_FROM_PARENT = "calledFromParent"; private static final String NOT_CALLED_FROM_PARENT = "notCalledFromParent"; @@ -488,7 +420,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final Set<String> SYSTEM_SETTINGS_WHITELIST; private static final Set<Integer> DA_DISALLOWED_POLICIES; // A collection of user restrictions that are deprecated and should simply be ignored. - private static final Set<String> DEPRECATED_USER_RESTRICTIONS; private static final String AB_DEVICE_KEY = "ro.build.ab_update"; static { @@ -532,10 +463,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES); DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD); DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); - - DEPRECATED_USER_RESTRICTIONS = Sets.newHashSet( - UserManager.DISALLOW_ADD_MANAGED_PROFILE, - UserManager.DISALLOW_REMOVE_MANAGED_PROFILE); } /** @@ -791,76 +718,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - public static class DevicePolicyData { - int mFailedPasswordAttempts = 0; - boolean mPasswordValidAtLastCheckpoint = true; - - int mUserHandle; - int mPasswordOwner = -1; - long mLastMaximumTimeToLock = -1; - boolean mUserSetupComplete = false; - boolean mPaired = false; - int mUserProvisioningState; - int mPermissionPolicy; - - boolean mDeviceProvisioningConfigApplied = false; - - final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>(); - final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>(); - final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>(); - - // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead. - final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>(); - - // This is the list of component allowed to start lock task mode. - List<String> mLockTaskPackages = new ArrayList<>(); - - // List of packages protected by device owner - List<String> mUserControlDisabledPackages = new ArrayList<>(); - - // Bitfield of feature flags to be enabled during LockTask mode. - // We default on the power button menu, in order to be consistent with pre-P behaviour. - int mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS; - - boolean mStatusBarDisabled = false; - - ComponentName mRestrictionsProvider; - - // Map of delegate package to delegation scopes - final ArrayMap<String, List<String>> mDelegationMap = new ArrayMap<>(); - - boolean doNotAskCredentialsOnBoot = false; - - Set<String> mAffiliationIds = new ArraySet<>(); - - long mLastSecurityLogRetrievalTime = -1; - - long mLastBugReportRequestTime = -1; - - long mLastNetworkLogsRetrievalTime = -1; - - boolean mCurrentInputMethodSet = false; - - boolean mSecondaryLockscreenEnabled = false; - - // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead. - Set<String> mOwnerInstalledCaCerts = new ArraySet<>(); - - // Used for initialization of users created by createAndManageUser. - boolean mAdminBroadcastPending = false; - PersistableBundle mInitBundle = null; - - long mPasswordTokenHandle = 0; - - // Whether user's apps are suspended. This flag should only be written AFTER all the needed - // apps were suspended or unsuspended. - boolean mAppsSuspended = false; - - public DevicePolicyData(int userHandle) { - mUserHandle = userHandle; - } - } - @GuardedBy("getLockObject()") final SparseArray<DevicePolicyData> mUserData = new SparseArray<>(); @@ -1045,1002 +902,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - static class ActiveAdmin { - private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features"; - private static final String TAG_TEST_ONLY_ADMIN = "test-only-admin"; - private static final String TAG_DISABLE_CAMERA = "disable-camera"; - private static final String TAG_DISABLE_CALLER_ID = "disable-caller-id"; - private static final String TAG_DISABLE_CONTACTS_SEARCH = "disable-contacts-search"; - private static final String TAG_DISABLE_BLUETOOTH_CONTACT_SHARING - = "disable-bt-contacts-sharing"; - private static final String TAG_DISABLE_SCREEN_CAPTURE = "disable-screen-capture"; - private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management"; - private static final String TAG_REQUIRE_AUTO_TIME = "require_auto_time"; - private static final String TAG_FORCE_EPHEMERAL_USERS = "force_ephemeral_users"; - private static final String TAG_IS_NETWORK_LOGGING_ENABLED = "is_network_logging_enabled"; - private static final String TAG_ACCOUNT_TYPE = "account-type"; - private static final String TAG_PERMITTED_ACCESSIBILITY_SERVICES - = "permitted-accessiblity-services"; - private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested"; - private static final String TAG_MANAGE_TRUST_AGENT_FEATURES = "manage-trust-agent-features"; - private static final String TAG_TRUST_AGENT_COMPONENT_OPTIONS = "trust-agent-component-options"; - private static final String TAG_TRUST_AGENT_COMPONENT = "component"; - private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date"; - private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout"; - private static final String TAG_GLOBAL_PROXY_EXCLUSION_LIST = "global-proxy-exclusion-list"; - private static final String TAG_GLOBAL_PROXY_SPEC = "global-proxy-spec"; - private static final String TAG_SPECIFIES_GLOBAL_PROXY = "specifies-global-proxy"; - private static final String TAG_PERMITTED_IMES = "permitted-imes"; - private static final String TAG_PERMITTED_NOTIFICATION_LISTENERS = - "permitted-notification-listeners"; - private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe"; - private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock"; - private static final String TAG_STRONG_AUTH_UNLOCK_TIMEOUT = "strong-auth-unlock-timeout"; - private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter"; - private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols"; - private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric"; - private static final String TAG_MIN_PASSWORD_LETTERS = "min-password-letters"; - private static final String TAG_MIN_PASSWORD_LOWERCASE = "min-password-lowercase"; - private static final String TAG_MIN_PASSWORD_UPPERCASE = "min-password-uppercase"; - private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length"; - private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length"; - private static final String ATTR_VALUE = "value"; - private static final String TAG_PASSWORD_QUALITY = "password-quality"; - private static final String TAG_POLICIES = "policies"; - private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS = - "cross-profile-widget-providers"; - private static final String TAG_PROVIDER = "provider"; - private static final String TAG_PACKAGE_LIST_ITEM = "item"; - private static final String TAG_KEEP_UNINSTALLED_PACKAGES = "keep-uninstalled-packages"; - private static final String TAG_USER_RESTRICTIONS = "user-restrictions"; - private static final String TAG_DEFAULT_ENABLED_USER_RESTRICTIONS = - "default-enabled-user-restrictions"; - private static final String TAG_RESTRICTION = "restriction"; - private static final String TAG_SHORT_SUPPORT_MESSAGE = "short-support-message"; - private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message"; - private static final String TAG_PARENT_ADMIN = "parent-admin"; - private static final String TAG_ORGANIZATION_COLOR = "organization-color"; - private static final String TAG_ORGANIZATION_NAME = "organization-name"; - private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification"; - private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications"; - private static final String TAG_IS_LOGOUT_ENABLED = "is_logout_enabled"; - private static final String TAG_START_USER_SESSION_MESSAGE = "start_user_session_message"; - private static final String TAG_END_USER_SESSION_MESSAGE = "end_user_session_message"; - private static final String TAG_METERED_DATA_DISABLED_PACKAGES = - "metered_data_disabled_packages"; - private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES = - "cross-profile-calendar-packages"; - private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL = - "cross-profile-calendar-packages-null"; - private static final String TAG_CROSS_PROFILE_PACKAGES = "cross-profile-packages"; - private static final String TAG_FACTORY_RESET_PROTECTION_POLICY = - "factory_reset_protection_policy"; - private static final String TAG_SUSPEND_PERSONAL_APPS = "suspend-personal-apps"; - private static final String TAG_PROFILE_MAXIMUM_TIME_OFF = "profile-max-time-off"; - private static final String TAG_PROFILE_OFF_DEADLINE = "profile-off-deadline"; - private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn-package"; - private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown"; - private static final String TAG_COMMON_CRITERIA_MODE = "common-criteria-mode"; - DeviceAdminInfo info; - - - static final int DEF_PASSWORD_HISTORY_LENGTH = 0; - int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH; - - @NonNull - PasswordPolicy mPasswordPolicy = new PasswordPolicy(); - - @Nullable - FactoryResetProtectionPolicy mFactoryResetProtectionPolicy = null; - - static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0; - long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK; - - long strongAuthUnlockTimeout = 0; // admin doesn't participate by default - - static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0; - int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE; - - static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0; - long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT; - - static final long DEF_PASSWORD_EXPIRATION_DATE = 0; - long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE; - - static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none - - int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED; - - boolean encryptionRequested = false; - boolean testOnlyAdmin = false; - boolean disableCamera = false; - boolean disableCallerId = false; - boolean disableContactsSearch = false; - boolean disableBluetoothContactSharing = true; - boolean disableScreenCapture = false; // Can only be set by a device/profile owner. - boolean requireAutoTime = false; // Can only be set by a device owner. - boolean forceEphemeralUsers = false; // Can only be set by a device owner. - boolean isNetworkLoggingEnabled = false; // Can only be set by a device owner. - boolean isLogoutEnabled = false; // Can only be set by a device owner. - - // one notification after enabling + one more after reboots - static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 2; - int numNetworkLoggingNotifications = 0; - long lastNetworkLoggingNotificationTimeMs = 0; // Time in milliseconds since epoch - - ActiveAdmin parentAdmin; - final boolean isParent; - - static class TrustAgentInfo { - public PersistableBundle options; - TrustAgentInfo(PersistableBundle bundle) { - options = bundle; - } - } - - // The list of packages which are not allowed to use metered data. - List<String> meteredDisabledPackages; - - final Set<String> accountTypesWithManagementDisabled = new ArraySet<>(); - - // The list of permitted accessibility services package namesas set by a profile - // or device owner. Null means all accessibility services are allowed, empty means - // none except system services are allowed. - List<String> permittedAccessiblityServices; - - // The list of permitted input methods package names as set by a profile or device owner. - // Null means all input methods are allowed, empty means none except system imes are - // allowed. - List<String> permittedInputMethods; - - // The list of packages allowed to use a NotificationListenerService to receive events for - // notifications from this user. Null means that all packages are allowed. Empty list means - // that only packages from the system are allowed. - List<String> permittedNotificationListeners; - - // List of package names to keep cached. - List<String> keepUninstalledPackages; - - // TODO: review implementation decisions with frameworks team - boolean specifiesGlobalProxy = false; - String globalProxySpec = null; - String globalProxyExclusionList = null; - - @NonNull ArrayMap<String, TrustAgentInfo> trustAgentInfos = new ArrayMap<>(); - - List<String> crossProfileWidgetProviders; - - Bundle userRestrictions; - - // User restrictions that have already been enabled by default for this admin (either when - // setting the device or profile owner, or during a system update if one of those "enabled - // by default" restrictions is newly added). - final Set<String> defaultEnabledRestrictionsAlreadySet = new ArraySet<>(); - - // Support text provided by the admin to display to the user. - CharSequence shortSupportMessage = null; - CharSequence longSupportMessage = null; - - // Background color of confirm credentials screen. Default: teal. - static final int DEF_ORGANIZATION_COLOR = Color.parseColor("#00796B"); - int organizationColor = DEF_ORGANIZATION_COLOR; - - // Default title of confirm credentials screen - String organizationName = null; - - // Message for user switcher - String startUserSessionMessage = null; - String endUserSessionMessage = null; - - // The whitelist of packages that can access cross profile calendar APIs. - // This whitelist should be in default an empty list, which indicates that no package - // is whitelisted. - List<String> mCrossProfileCalendarPackages = Collections.emptyList(); - - // The whitelist of packages that the admin has enabled to be able to request consent from - // the user to communicate cross-profile. By default, no packages are whitelisted, which is - // represented as an empty list. - List<String> mCrossProfilePackages = Collections.emptyList(); - - // Whether the admin explicitly requires personal apps to be suspended - boolean mSuspendPersonalApps = false; - // Maximum time the profile owned by this admin can be off. - long mProfileMaximumTimeOffMillis = 0; - // Time by which the profile should be turned on according to System.currentTimeMillis(). - long mProfileOffDeadline = 0; - - public String mAlwaysOnVpnPackage; - public boolean mAlwaysOnVpnLockdown; - boolean mCommonCriteriaMode; - - ActiveAdmin(DeviceAdminInfo _info, boolean parent) { - info = _info; - isParent = parent; - } - - ActiveAdmin getParentActiveAdmin() { - Preconditions.checkState(!isParent); - - if (parentAdmin == null) { - parentAdmin = new ActiveAdmin(info, /* parent */ true); - } - return parentAdmin; - } - - boolean hasParentActiveAdmin() { - return parentAdmin != null; - } - - int getUid() { return info.getActivityInfo().applicationInfo.uid; } - - public UserHandle getUserHandle() { - return UserHandle.of(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid)); - } - - void writeToXml(XmlSerializer out) - throws IllegalArgumentException, IllegalStateException, IOException { - out.startTag(null, TAG_POLICIES); - info.writePoliciesToXml(out); - out.endTag(null, TAG_POLICIES); - if (mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED) { - writeAttributeValueToXml( - out, TAG_PASSWORD_QUALITY, mPasswordPolicy.quality); - if (mPasswordPolicy.length != PasswordPolicy.DEF_MINIMUM_LENGTH) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_LENGTH, mPasswordPolicy.length); - } - if (mPasswordPolicy.upperCase != PasswordPolicy.DEF_MINIMUM_UPPER_CASE) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_UPPERCASE, mPasswordPolicy.upperCase); - } - if (mPasswordPolicy.lowerCase != PasswordPolicy.DEF_MINIMUM_LOWER_CASE) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_LOWERCASE, mPasswordPolicy.lowerCase); - } - if (mPasswordPolicy.letters != PasswordPolicy.DEF_MINIMUM_LETTERS) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_LETTERS, mPasswordPolicy.letters); - } - if (mPasswordPolicy.numeric != PasswordPolicy.DEF_MINIMUM_NUMERIC) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_NUMERIC, mPasswordPolicy.numeric); - } - if (mPasswordPolicy.symbols != PasswordPolicy.DEF_MINIMUM_SYMBOLS) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_SYMBOLS, mPasswordPolicy.symbols); - } - if (mPasswordPolicy.nonLetter > PasswordPolicy.DEF_MINIMUM_NON_LETTER) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_NONLETTER, mPasswordPolicy.nonLetter); - } - } - if (passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) { - writeAttributeValueToXml( - out, TAG_PASSWORD_HISTORY_LENGTH, passwordHistoryLength); - } - if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) { - writeAttributeValueToXml( - out, TAG_MAX_TIME_TO_UNLOCK, maximumTimeToUnlock); - } - if (strongAuthUnlockTimeout != DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) { - writeAttributeValueToXml( - out, TAG_STRONG_AUTH_UNLOCK_TIMEOUT, strongAuthUnlockTimeout); - } - if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) { - writeAttributeValueToXml( - out, TAG_MAX_FAILED_PASSWORD_WIPE, maximumFailedPasswordsForWipe); - } - if (specifiesGlobalProxy) { - writeAttributeValueToXml( - out, TAG_SPECIFIES_GLOBAL_PROXY, specifiesGlobalProxy); - if (globalProxySpec != null) { - writeAttributeValueToXml(out, TAG_GLOBAL_PROXY_SPEC, globalProxySpec); - } - if (globalProxyExclusionList != null) { - writeAttributeValueToXml( - out, TAG_GLOBAL_PROXY_EXCLUSION_LIST, globalProxyExclusionList); - } - } - if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) { - writeAttributeValueToXml( - out, TAG_PASSWORD_EXPIRATION_TIMEOUT, passwordExpirationTimeout); - } - if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) { - writeAttributeValueToXml( - out, TAG_PASSWORD_EXPIRATION_DATE, passwordExpirationDate); - } - if (encryptionRequested) { - writeAttributeValueToXml( - out, TAG_ENCRYPTION_REQUESTED, encryptionRequested); - } - if (testOnlyAdmin) { - writeAttributeValueToXml( - out, TAG_TEST_ONLY_ADMIN, testOnlyAdmin); - } - if (disableCamera) { - writeAttributeValueToXml( - out, TAG_DISABLE_CAMERA, disableCamera); - } - if (disableCallerId) { - writeAttributeValueToXml( - out, TAG_DISABLE_CALLER_ID, disableCallerId); - } - if (disableContactsSearch) { - writeAttributeValueToXml( - out, TAG_DISABLE_CONTACTS_SEARCH, disableContactsSearch); - } - if (!disableBluetoothContactSharing) { - writeAttributeValueToXml( - out, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING, disableBluetoothContactSharing); - } - if (disableScreenCapture) { - writeAttributeValueToXml( - out, TAG_DISABLE_SCREEN_CAPTURE, disableScreenCapture); - } - if (requireAutoTime) { - writeAttributeValueToXml( - out, TAG_REQUIRE_AUTO_TIME, requireAutoTime); - } - if (forceEphemeralUsers) { - writeAttributeValueToXml( - out, TAG_FORCE_EPHEMERAL_USERS, forceEphemeralUsers); - } - if (isNetworkLoggingEnabled) { - out.startTag(null, TAG_IS_NETWORK_LOGGING_ENABLED); - out.attribute(null, ATTR_VALUE, Boolean.toString(isNetworkLoggingEnabled)); - out.attribute(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS, - Integer.toString(numNetworkLoggingNotifications)); - out.attribute(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION, - Long.toString(lastNetworkLoggingNotificationTimeMs)); - out.endTag(null, TAG_IS_NETWORK_LOGGING_ENABLED); - } - if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) { - writeAttributeValueToXml( - out, TAG_DISABLE_KEYGUARD_FEATURES, disabledKeyguardFeatures); - } - if (!accountTypesWithManagementDisabled.isEmpty()) { - writeAttributeValuesToXml( - out, TAG_DISABLE_ACCOUNT_MANAGEMENT, TAG_ACCOUNT_TYPE, - accountTypesWithManagementDisabled); - } - if (!trustAgentInfos.isEmpty()) { - Set<Entry<String, TrustAgentInfo>> set = trustAgentInfos.entrySet(); - out.startTag(null, TAG_MANAGE_TRUST_AGENT_FEATURES); - for (Entry<String, TrustAgentInfo> entry : set) { - TrustAgentInfo trustAgentInfo = entry.getValue(); - out.startTag(null, TAG_TRUST_AGENT_COMPONENT); - out.attribute(null, ATTR_VALUE, entry.getKey()); - if (trustAgentInfo.options != null) { - out.startTag(null, TAG_TRUST_AGENT_COMPONENT_OPTIONS); - try { - trustAgentInfo.options.saveToXml(out); - } catch (XmlPullParserException e) { - Log.e(LOG_TAG, "Failed to save TrustAgent options", e); - } - out.endTag(null, TAG_TRUST_AGENT_COMPONENT_OPTIONS); - } - out.endTag(null, TAG_TRUST_AGENT_COMPONENT); - } - out.endTag(null, TAG_MANAGE_TRUST_AGENT_FEATURES); - } - if (crossProfileWidgetProviders != null && !crossProfileWidgetProviders.isEmpty()) { - writeAttributeValuesToXml( - out, TAG_CROSS_PROFILE_WIDGET_PROVIDERS, TAG_PROVIDER, - crossProfileWidgetProviders); - } - writePackageListToXml(out, TAG_PERMITTED_ACCESSIBILITY_SERVICES, - permittedAccessiblityServices); - writePackageListToXml(out, TAG_PERMITTED_IMES, permittedInputMethods); - writePackageListToXml(out, TAG_PERMITTED_NOTIFICATION_LISTENERS, - permittedNotificationListeners); - writePackageListToXml(out, TAG_KEEP_UNINSTALLED_PACKAGES, keepUninstalledPackages); - writePackageListToXml(out, TAG_METERED_DATA_DISABLED_PACKAGES, meteredDisabledPackages); - if (hasUserRestrictions()) { - UserRestrictionsUtils.writeRestrictions( - out, userRestrictions, TAG_USER_RESTRICTIONS); - } - if (!defaultEnabledRestrictionsAlreadySet.isEmpty()) { - writeAttributeValuesToXml(out, TAG_DEFAULT_ENABLED_USER_RESTRICTIONS, - TAG_RESTRICTION, - defaultEnabledRestrictionsAlreadySet); - } - if (!TextUtils.isEmpty(shortSupportMessage)) { - writeTextToXml(out, TAG_SHORT_SUPPORT_MESSAGE, shortSupportMessage.toString()); - } - if (!TextUtils.isEmpty(longSupportMessage)) { - writeTextToXml(out, TAG_LONG_SUPPORT_MESSAGE, longSupportMessage.toString()); - } - if (parentAdmin != null) { - out.startTag(null, TAG_PARENT_ADMIN); - parentAdmin.writeToXml(out); - out.endTag(null, TAG_PARENT_ADMIN); - } - if (organizationColor != DEF_ORGANIZATION_COLOR) { - writeAttributeValueToXml(out, TAG_ORGANIZATION_COLOR, organizationColor); - } - if (organizationName != null) { - writeTextToXml(out, TAG_ORGANIZATION_NAME, organizationName); - } - if (isLogoutEnabled) { - writeAttributeValueToXml(out, TAG_IS_LOGOUT_ENABLED, isLogoutEnabled); - } - if (startUserSessionMessage != null) { - writeTextToXml(out, TAG_START_USER_SESSION_MESSAGE, startUserSessionMessage); - } - if (endUserSessionMessage != null) { - writeTextToXml(out, TAG_END_USER_SESSION_MESSAGE, endUserSessionMessage); - } - if (mCrossProfileCalendarPackages == null) { - out.startTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL); - out.endTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL); - } else { - writePackageListToXml(out, TAG_CROSS_PROFILE_CALENDAR_PACKAGES, - mCrossProfileCalendarPackages); - } - writePackageListToXml(out, TAG_CROSS_PROFILE_PACKAGES, mCrossProfilePackages); - if (mFactoryResetProtectionPolicy != null) { - out.startTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); - mFactoryResetProtectionPolicy.writeToXml(out); - out.endTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); - } - if (mSuspendPersonalApps) { - writeAttributeValueToXml(out, TAG_SUSPEND_PERSONAL_APPS, mSuspendPersonalApps); - } - if (mProfileMaximumTimeOffMillis != 0) { - writeAttributeValueToXml(out, TAG_PROFILE_MAXIMUM_TIME_OFF, - mProfileMaximumTimeOffMillis); - } - if (mProfileMaximumTimeOffMillis != 0) { - writeAttributeValueToXml(out, TAG_PROFILE_OFF_DEADLINE, mProfileOffDeadline); - } - if (!TextUtils.isEmpty(mAlwaysOnVpnPackage)) { - writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_PACKAGE, mAlwaysOnVpnPackage); - } - if (mAlwaysOnVpnLockdown) { - writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_LOCKDOWN, mAlwaysOnVpnLockdown); - } - if (mCommonCriteriaMode) { - writeAttributeValueToXml(out, TAG_COMMON_CRITERIA_MODE, mCommonCriteriaMode); - } - } - - void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException { - out.startTag(null, tag); - out.text(text); - out.endTag(null, tag); - } - - void writePackageListToXml(XmlSerializer out, String outerTag, - List<String> packageList) - throws IllegalArgumentException, IllegalStateException, IOException { - if (packageList == null) { - return; - } - writeAttributeValuesToXml(out, outerTag, TAG_PACKAGE_LIST_ITEM, packageList); - } - - void writeAttributeValueToXml(XmlSerializer out, String tag, String value) - throws IOException { - out.startTag(null, tag); - out.attribute(null, ATTR_VALUE, value); - out.endTag(null, tag); - } - - void writeAttributeValueToXml(XmlSerializer out, String tag, int value) - throws IOException { - out.startTag(null, tag); - out.attribute(null, ATTR_VALUE, Integer.toString(value)); - out.endTag(null, tag); - } - - void writeAttributeValueToXml(XmlSerializer out, String tag, long value) - throws IOException { - out.startTag(null, tag); - out.attribute(null, ATTR_VALUE, Long.toString(value)); - out.endTag(null, tag); - } - - void writeAttributeValueToXml(XmlSerializer out, String tag, boolean value) - throws IOException { - out.startTag(null, tag); - out.attribute(null, ATTR_VALUE, Boolean.toString(value)); - out.endTag(null, tag); - } - - void writeAttributeValuesToXml(XmlSerializer out, String outerTag, String innerTag, - @NonNull Collection<String> values) throws IOException { - out.startTag(null, outerTag); - for (String value : values) { - out.startTag(null, innerTag); - out.attribute(null, ATTR_VALUE, value); - out.endTag(null, innerTag); - } - out.endTag(null, outerTag); - } - - void readFromXml(XmlPullParser parser, boolean shouldOverridePolicies) - throws XmlPullParserException, IOException { - int outerDepth = parser.getDepth(); - int type; - while ((type=parser.next()) != END_DOCUMENT - && (type != END_TAG || parser.getDepth() > outerDepth)) { - if (type == END_TAG || type == TEXT) { - continue; - } - String tag = parser.getName(); - if (TAG_POLICIES.equals(tag)) { - if (shouldOverridePolicies) { - Log.d(LOG_TAG, "Overriding device admin policies from XML."); - info.readPoliciesFromXml(parser); - } - } else if (TAG_PASSWORD_QUALITY.equals(tag)) { - mPasswordPolicy.quality = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) { - mPasswordPolicy.length = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) { - passwordHistoryLength = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) { - mPasswordPolicy.upperCase = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) { - mPasswordPolicy.lowerCase = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) { - mPasswordPolicy.letters = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) { - mPasswordPolicy.numeric = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) { - mPasswordPolicy.symbols = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) { - mPasswordPolicy.nonLetter = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - }else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) { - maximumTimeToUnlock = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_STRONG_AUTH_UNLOCK_TIMEOUT.equals(tag)) { - strongAuthUnlockTimeout = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) { - maximumFailedPasswordsForWipe = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_SPECIFIES_GLOBAL_PROXY.equals(tag)) { - specifiesGlobalProxy = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_GLOBAL_PROXY_SPEC.equals(tag)) { - globalProxySpec = - parser.getAttributeValue(null, ATTR_VALUE); - } else if (TAG_GLOBAL_PROXY_EXCLUSION_LIST.equals(tag)) { - globalProxyExclusionList = - parser.getAttributeValue(null, ATTR_VALUE); - } else if (TAG_PASSWORD_EXPIRATION_TIMEOUT.equals(tag)) { - passwordExpirationTimeout = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_PASSWORD_EXPIRATION_DATE.equals(tag)) { - passwordExpirationDate = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) { - encryptionRequested = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_TEST_ONLY_ADMIN.equals(tag)) { - testOnlyAdmin = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_CAMERA.equals(tag)) { - disableCamera = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_CALLER_ID.equals(tag)) { - disableCallerId = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_CONTACTS_SEARCH.equals(tag)) { - disableContactsSearch = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_BLUETOOTH_CONTACT_SHARING.equals(tag)) { - disableBluetoothContactSharing = Boolean.parseBoolean(parser - .getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_SCREEN_CAPTURE.equals(tag)) { - disableScreenCapture = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_REQUIRE_AUTO_TIME.equals(tag)) { - requireAutoTime = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_FORCE_EPHEMERAL_USERS.equals(tag)) { - forceEphemeralUsers = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_IS_NETWORK_LOGGING_ENABLED.equals(tag)) { - isNetworkLoggingEnabled = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - lastNetworkLoggingNotificationTimeMs = Long.parseLong( - parser.getAttributeValue(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION)); - numNetworkLoggingNotifications = Integer.parseInt( - parser.getAttributeValue(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS)); - } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) { - disabledKeyguardFeatures = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_ACCOUNT_MANAGEMENT.equals(tag)) { - readAttributeValues( - parser, TAG_ACCOUNT_TYPE, accountTypesWithManagementDisabled); - } else if (TAG_MANAGE_TRUST_AGENT_FEATURES.equals(tag)) { - trustAgentInfos = getAllTrustAgentInfos(parser, tag); - } else if (TAG_CROSS_PROFILE_WIDGET_PROVIDERS.equals(tag)) { - crossProfileWidgetProviders = new ArrayList<>(); - readAttributeValues(parser, TAG_PROVIDER, crossProfileWidgetProviders); - } else if (TAG_PERMITTED_ACCESSIBILITY_SERVICES.equals(tag)) { - permittedAccessiblityServices = readPackageList(parser, tag); - } else if (TAG_PERMITTED_IMES.equals(tag)) { - permittedInputMethods = readPackageList(parser, tag); - } else if (TAG_PERMITTED_NOTIFICATION_LISTENERS.equals(tag)) { - permittedNotificationListeners = readPackageList(parser, tag); - } else if (TAG_KEEP_UNINSTALLED_PACKAGES.equals(tag)) { - keepUninstalledPackages = readPackageList(parser, tag); - } else if (TAG_METERED_DATA_DISABLED_PACKAGES.equals(tag)) { - meteredDisabledPackages = readPackageList(parser, tag); - } else if (TAG_USER_RESTRICTIONS.equals(tag)) { - userRestrictions = UserRestrictionsUtils.readRestrictions(parser); - } else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) { - readAttributeValues( - parser, TAG_RESTRICTION, defaultEnabledRestrictionsAlreadySet); - } else if (TAG_SHORT_SUPPORT_MESSAGE.equals(tag)) { - type = parser.next(); - if (type == XmlPullParser.TEXT) { - shortSupportMessage = parser.getText(); - } else { - Log.w(LOG_TAG, "Missing text when loading short support message"); - } - } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) { - type = parser.next(); - if (type == XmlPullParser.TEXT) { - longSupportMessage = parser.getText(); - } else { - Log.w(LOG_TAG, "Missing text when loading long support message"); - } - } else if (TAG_PARENT_ADMIN.equals(tag)) { - Preconditions.checkState(!isParent); - parentAdmin = new ActiveAdmin(info, /* parent */ true); - parentAdmin.readFromXml(parser, shouldOverridePolicies); - } else if (TAG_ORGANIZATION_COLOR.equals(tag)) { - organizationColor = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_ORGANIZATION_NAME.equals(tag)) { - type = parser.next(); - if (type == XmlPullParser.TEXT) { - organizationName = parser.getText(); - } else { - Log.w(LOG_TAG, "Missing text when loading organization name"); - } - } else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) { - isLogoutEnabled = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_START_USER_SESSION_MESSAGE.equals(tag)) { - type = parser.next(); - if (type == XmlPullParser.TEXT) { - startUserSessionMessage = parser.getText(); - } else { - Log.w(LOG_TAG, "Missing text when loading start session message"); - } - } else if (TAG_END_USER_SESSION_MESSAGE.equals(tag)) { - type = parser.next(); - if (type == XmlPullParser.TEXT) { - endUserSessionMessage = parser.getText(); - } else { - Log.w(LOG_TAG, "Missing text when loading end session message"); - } - } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES.equals(tag)) { - mCrossProfileCalendarPackages = readPackageList(parser, tag); - } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL.equals(tag)) { - mCrossProfileCalendarPackages = null; - } else if (TAG_CROSS_PROFILE_PACKAGES.equals(tag)) { - mCrossProfilePackages = readPackageList(parser, tag); - } else if (TAG_FACTORY_RESET_PROTECTION_POLICY.equals(tag)) { - mFactoryResetProtectionPolicy = FactoryResetProtectionPolicy.readFromXml( - parser); - } else if (TAG_SUSPEND_PERSONAL_APPS.equals(tag)) { - mSuspendPersonalApps = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_PROFILE_MAXIMUM_TIME_OFF.equals(tag)) { - mProfileMaximumTimeOffMillis = - Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) { - mProfileOffDeadline = - Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_ALWAYS_ON_VPN_PACKAGE.equals(tag)) { - mAlwaysOnVpnPackage = parser.getAttributeValue(null, ATTR_VALUE); - } else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) { - mAlwaysOnVpnLockdown = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_COMMON_CRITERIA_MODE.equals(tag)) { - mCommonCriteriaMode = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else { - Slog.w(LOG_TAG, "Unknown admin tag: " + tag); - XmlUtils.skipCurrentTag(parser); - } - } - } - - private List<String> readPackageList(XmlPullParser parser, - String tag) throws XmlPullParserException, IOException { - List<String> result = new ArrayList<String>(); - int outerDepth = parser.getDepth(); - int outerType; - while ((outerType=parser.next()) != XmlPullParser.END_DOCUMENT - && (outerType != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (outerType == XmlPullParser.END_TAG || outerType == XmlPullParser.TEXT) { - continue; - } - String outerTag = parser.getName(); - if (TAG_PACKAGE_LIST_ITEM.equals(outerTag)) { - String packageName = parser.getAttributeValue(null, ATTR_VALUE); - if (packageName != null) { - result.add(packageName); - } else { - Slog.w(LOG_TAG, "Package name missing under " + outerTag); - } - } else { - Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + outerTag); - } - } - return result; - } - - private void readAttributeValues( - XmlPullParser parser, String tag, Collection<String> result) - throws XmlPullParserException, IOException { - result.clear(); - int outerDepthDAM = parser.getDepth(); - int typeDAM; - while ((typeDAM=parser.next()) != END_DOCUMENT - && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { - if (typeDAM == END_TAG || typeDAM == TEXT) { - continue; - } - String tagDAM = parser.getName(); - if (tag.equals(tagDAM)) { - result.add(parser.getAttributeValue(null, ATTR_VALUE)); - } else { - Slog.e(LOG_TAG, "Expected tag " + tag + " but found " + tagDAM); - } - } - } - - @NonNull - private ArrayMap<String, TrustAgentInfo> getAllTrustAgentInfos( - XmlPullParser parser, String tag) throws XmlPullParserException, IOException { - int outerDepthDAM = parser.getDepth(); - int typeDAM; - final ArrayMap<String, TrustAgentInfo> result = new ArrayMap<>(); - while ((typeDAM=parser.next()) != END_DOCUMENT - && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { - if (typeDAM == END_TAG || typeDAM == TEXT) { - continue; - } - String tagDAM = parser.getName(); - if (TAG_TRUST_AGENT_COMPONENT.equals(tagDAM)) { - final String component = parser.getAttributeValue(null, ATTR_VALUE); - final TrustAgentInfo trustAgentInfo = getTrustAgentInfo(parser, tag); - result.put(component, trustAgentInfo); - } else { - Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + tagDAM); - } - } - return result; - } - - private TrustAgentInfo getTrustAgentInfo(XmlPullParser parser, String tag) - throws XmlPullParserException, IOException { - int outerDepthDAM = parser.getDepth(); - int typeDAM; - TrustAgentInfo result = new TrustAgentInfo(null); - while ((typeDAM=parser.next()) != END_DOCUMENT - && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { - if (typeDAM == END_TAG || typeDAM == TEXT) { - continue; - } - String tagDAM = parser.getName(); - if (TAG_TRUST_AGENT_COMPONENT_OPTIONS.equals(tagDAM)) { - result.options = PersistableBundle.restoreFromXml(parser); - } else { - Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + tagDAM); - } - } - return result; - } - - boolean hasUserRestrictions() { - return userRestrictions != null && userRestrictions.size() > 0; - } - - Bundle ensureUserRestrictions() { - if (userRestrictions == null) { - userRestrictions = new Bundle(); - } - return userRestrictions; - } - - public void transfer(DeviceAdminInfo deviceAdminInfo) { - if (hasParentActiveAdmin()) { - parentAdmin.info = deviceAdminInfo; - } - info = deviceAdminInfo; - } - - Bundle addSyntheticRestrictions(Bundle restrictions) { - if (disableCamera) { - restrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); - } - if (requireAutoTime) { - restrictions.putBoolean(UserManager.DISALLOW_CONFIG_DATE_TIME, true); - } - return restrictions; - } - - static Bundle removeDeprecatedRestrictions(Bundle restrictions) { - for (String deprecatedRestriction: DEPRECATED_USER_RESTRICTIONS) { - restrictions.remove(deprecatedRestriction); - } - return restrictions; - } - - static Bundle filterRestrictions(Bundle restrictions, Predicate<String> filter) { - Bundle result = new Bundle(); - for (String key : restrictions.keySet()) { - if (!restrictions.getBoolean(key)) { - continue; - } - if (filter.test(key)) { - result.putBoolean(key, true); - } - } - return result; - } - - Bundle getEffectiveRestrictions() { - return addSyntheticRestrictions( - removeDeprecatedRestrictions(new Bundle(ensureUserRestrictions()))); - } - - Bundle getLocalUserRestrictions(int adminType) { - return filterRestrictions(getEffectiveRestrictions(), - key -> UserRestrictionsUtils.isLocal(adminType, key)); - } - - Bundle getGlobalUserRestrictions(int adminType) { - return filterRestrictions(getEffectiveRestrictions(), - key -> UserRestrictionsUtils.isGlobal(adminType, key)); - } - - void dump(IndentingPrintWriter pw) { - pw.print("uid="); pw.println(getUid()); - pw.print("testOnlyAdmin="); - pw.println(testOnlyAdmin); - pw.println("policies:"); - ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies(); - if (pols != null) { - pw.increaseIndent(); - for (int i=0; i<pols.size(); i++) { - pw.println(pols.get(i).tag); - } - pw.decreaseIndent(); - } - pw.print("passwordQuality=0x"); - pw.println(Integer.toHexString(mPasswordPolicy.quality)); - pw.print("minimumPasswordLength="); - pw.println(mPasswordPolicy.length); - pw.print("passwordHistoryLength="); - pw.println(passwordHistoryLength); - pw.print("minimumPasswordUpperCase="); - pw.println(mPasswordPolicy.upperCase); - pw.print("minimumPasswordLowerCase="); - pw.println(mPasswordPolicy.lowerCase); - pw.print("minimumPasswordLetters="); - pw.println(mPasswordPolicy.letters); - pw.print("minimumPasswordNumeric="); - pw.println(mPasswordPolicy.numeric); - pw.print("minimumPasswordSymbols="); - pw.println(mPasswordPolicy.symbols); - pw.print("minimumPasswordNonLetter="); - pw.println(mPasswordPolicy.nonLetter); - pw.print("maximumTimeToUnlock="); - pw.println(maximumTimeToUnlock); - pw.print("strongAuthUnlockTimeout="); - pw.println(strongAuthUnlockTimeout); - pw.print("maximumFailedPasswordsForWipe="); - pw.println(maximumFailedPasswordsForWipe); - pw.print("specifiesGlobalProxy="); - pw.println(specifiesGlobalProxy); - pw.print("passwordExpirationTimeout="); - pw.println(passwordExpirationTimeout); - pw.print("passwordExpirationDate="); - pw.println(passwordExpirationDate); - if (globalProxySpec != null) { - pw.print("globalProxySpec="); - pw.println(globalProxySpec); - } - if (globalProxyExclusionList != null) { - pw.print("globalProxyEclusionList="); - pw.println(globalProxyExclusionList); - } - pw.print("encryptionRequested="); - pw.println(encryptionRequested); - pw.print("disableCamera="); - pw.println(disableCamera); - pw.print("disableCallerId="); - pw.println(disableCallerId); - pw.print("disableContactsSearch="); - pw.println(disableContactsSearch); - pw.print("disableBluetoothContactSharing="); - pw.println(disableBluetoothContactSharing); - pw.print("disableScreenCapture="); - pw.println(disableScreenCapture); - pw.print("requireAutoTime="); - pw.println(requireAutoTime); - pw.print("forceEphemeralUsers="); - pw.println(forceEphemeralUsers); - pw.print("isNetworkLoggingEnabled="); - pw.println(isNetworkLoggingEnabled); - pw.print("disabledKeyguardFeatures="); - pw.println(disabledKeyguardFeatures); - pw.print("crossProfileWidgetProviders="); - pw.println(crossProfileWidgetProviders); - if (permittedAccessiblityServices != null) { - pw.print("permittedAccessibilityServices="); - pw.println(permittedAccessiblityServices); - } - if (permittedInputMethods != null) { - pw.print("permittedInputMethods="); - pw.println(permittedInputMethods); - } - if (permittedNotificationListeners != null) { - pw.print("permittedNotificationListeners="); - pw.println(permittedNotificationListeners); - } - if (keepUninstalledPackages != null) { - pw.print("keepUninstalledPackages="); - pw.println(keepUninstalledPackages); - } - pw.print("organizationColor="); - pw.println(organizationColor); - if (organizationName != null) { - pw.print("organizationName="); - pw.println(organizationName); - } - pw.println("userRestrictions:"); - UserRestrictionsUtils.dumpRestrictions(pw, " ", userRestrictions); - pw.print("defaultEnabledRestrictionsAlreadySet="); - pw.println(defaultEnabledRestrictionsAlreadySet); - pw.print("isParent="); - pw.println(isParent); - if (parentAdmin != null) { - pw.println("parentAdmin:"); - pw.increaseIndent(); - parentAdmin.dump(pw); - pw.decreaseIndent(); - } - if (mCrossProfileCalendarPackages != null) { - pw.print("mCrossProfileCalendarPackages="); - pw.println(mCrossProfileCalendarPackages); - } - pw.print("mCrossProfilePackages="); - pw.println(mCrossProfilePackages); - pw.print("mSuspendPersonalApps="); - pw.println(mSuspendPersonalApps); - pw.print("mProfileMaximumTimeOffMillis="); - pw.println(mProfileMaximumTimeOffMillis); - pw.print("mProfileOffDeadline="); - pw.println(mProfileOffDeadline); - pw.print("mAlwaysOnVpnPackage="); - pw.println(mAlwaysOnVpnPackage); - pw.print("mAlwaysOnVpnLockdown="); - pw.println(mAlwaysOnVpnLockdown); - pw.print("mCommonCriteriaMode="); - pw.println(mCommonCriteriaMode); - } - } - private void handlePackagesChanged(@Nullable String packageName, int userHandle) { boolean removedAdmin = false; if (VERBOSE_LOG) { @@ -2073,7 +934,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } if (removedAdmin) { - validatePasswordOwnerLocked(policy); + policy.validatePasswordOwner(); } boolean removedDelegate = false; @@ -3514,13 +2375,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - - public DeviceAdminInfo findAdmin(final ComponentName adminName, final int userHandle, + private DeviceAdminInfo findAdmin(final ComponentName adminName, final int userHandle, boolean throwForMissingPermission) { - if (!mHasFeature) { - return null; - } - enforceFullCrossUsersPermission(userHandle); final ActivityInfo ai = mInjector.binderWithCleanCallingIdentity(() -> { try { return mIPackageManager.getReceiverInfo(adminName, @@ -3583,213 +2439,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void saveSettingsLocked(int userHandle) { - DevicePolicyData policy = getUserData(userHandle); - JournaledFile journal = makeJournaledFile(userHandle); - FileOutputStream stream = null; - try { - stream = new FileOutputStream(journal.chooseForWrite(), false); - XmlSerializer out = new FastXmlSerializer(); - out.setOutput(stream, StandardCharsets.UTF_8.name()); - out.startDocument(null, true); - - out.startTag(null, "policies"); - if (policy.mRestrictionsProvider != null) { - out.attribute(null, ATTR_PERMISSION_PROVIDER, - policy.mRestrictionsProvider.flattenToString()); - } - if (policy.mUserSetupComplete) { - out.attribute(null, ATTR_SETUP_COMPLETE, - Boolean.toString(true)); - } - if (policy.mPaired) { - out.attribute(null, ATTR_DEVICE_PAIRED, - Boolean.toString(true)); - } - if (policy.mDeviceProvisioningConfigApplied) { - out.attribute(null, ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED, - Boolean.toString(true)); - } - if (policy.mUserProvisioningState != DevicePolicyManager.STATE_USER_UNMANAGED) { - out.attribute(null, ATTR_PROVISIONING_STATE, - Integer.toString(policy.mUserProvisioningState)); - } - if (policy.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) { - out.attribute(null, ATTR_PERMISSION_POLICY, - Integer.toString(policy.mPermissionPolicy)); - } - - // Serialize delegations. - for (int i = 0; i < policy.mDelegationMap.size(); ++i) { - final String delegatePackage = policy.mDelegationMap.keyAt(i); - final List<String> scopes = policy.mDelegationMap.valueAt(i); - - // Every "delegation" tag serializes the information of one delegate-scope pair. - for (String scope : scopes) { - out.startTag(null, "delegation"); - out.attribute(null, "delegatePackage", delegatePackage); - out.attribute(null, "scope", scope); - out.endTag(null, "delegation"); - } - } - - final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin ap = policy.mAdminList.get(i); - if (ap != null) { - out.startTag(null, "admin"); - out.attribute(null, "name", ap.info.getComponent().flattenToString()); - ap.writeToXml(out); - out.endTag(null, "admin"); - } - } - - if (policy.mPasswordOwner >= 0) { - out.startTag(null, "password-owner"); - out.attribute(null, "value", Integer.toString(policy.mPasswordOwner)); - out.endTag(null, "password-owner"); - } - - if (policy.mFailedPasswordAttempts != 0) { - out.startTag(null, "failed-password-attempts"); - out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts)); - out.endTag(null, "failed-password-attempts"); - } - - // For FDE devices only, we save this flag so we can report on password sufficiency - // before the user enters their password for the first time after a reboot. For - // security reasons, we don't want to store the full set of active password metrics. - if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) { - out.startTag(null, TAG_PASSWORD_VALIDITY); - out.attribute(null, ATTR_VALUE, - Boolean.toString(policy.mPasswordValidAtLastCheckpoint)); - out.endTag(null, TAG_PASSWORD_VALIDITY); - } - - for (int i = 0; i < policy.mAcceptedCaCertificates.size(); i++) { - out.startTag(null, TAG_ACCEPTED_CA_CERTIFICATES); - out.attribute(null, ATTR_NAME, policy.mAcceptedCaCertificates.valueAt(i)); - out.endTag(null, TAG_ACCEPTED_CA_CERTIFICATES); - } - - for (int i=0; i<policy.mLockTaskPackages.size(); i++) { - String component = policy.mLockTaskPackages.get(i); - out.startTag(null, TAG_LOCK_TASK_COMPONENTS); - out.attribute(null, "name", component); - out.endTag(null, TAG_LOCK_TASK_COMPONENTS); - } - - if (policy.mLockTaskFeatures != DevicePolicyManager.LOCK_TASK_FEATURE_NONE) { - out.startTag(null, TAG_LOCK_TASK_FEATURES); - out.attribute(null, ATTR_VALUE, Integer.toString(policy.mLockTaskFeatures)); - out.endTag(null, TAG_LOCK_TASK_FEATURES); - } - - if (policy.mSecondaryLockscreenEnabled) { - out.startTag(null, TAG_SECONDARY_LOCK_SCREEN); - out.attribute(null, ATTR_VALUE, Boolean.toString(true)); - out.endTag(null, TAG_SECONDARY_LOCK_SCREEN); - } - - if (policy.mStatusBarDisabled) { - out.startTag(null, TAG_STATUS_BAR); - out.attribute(null, ATTR_DISABLED, Boolean.toString(policy.mStatusBarDisabled)); - out.endTag(null, TAG_STATUS_BAR); - } - - if (policy.doNotAskCredentialsOnBoot) { - out.startTag(null, DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML); - out.endTag(null, DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML); - } - - for (String id : policy.mAffiliationIds) { - out.startTag(null, TAG_AFFILIATION_ID); - out.attribute(null, ATTR_ID, id); - out.endTag(null, TAG_AFFILIATION_ID); - } - - if (policy.mLastSecurityLogRetrievalTime >= 0) { - out.startTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL); - out.attribute(null, ATTR_VALUE, - Long.toString(policy.mLastSecurityLogRetrievalTime)); - out.endTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL); - } - - if (policy.mLastBugReportRequestTime >= 0) { - out.startTag(null, TAG_LAST_BUG_REPORT_REQUEST); - out.attribute(null, ATTR_VALUE, - Long.toString(policy.mLastBugReportRequestTime)); - out.endTag(null, TAG_LAST_BUG_REPORT_REQUEST); - } - - if (policy.mLastNetworkLogsRetrievalTime >= 0) { - out.startTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL); - out.attribute(null, ATTR_VALUE, - Long.toString(policy.mLastNetworkLogsRetrievalTime)); - out.endTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL); - } - - if (policy.mAdminBroadcastPending) { - out.startTag(null, TAG_ADMIN_BROADCAST_PENDING); - out.attribute(null, ATTR_VALUE, - Boolean.toString(policy.mAdminBroadcastPending)); - out.endTag(null, TAG_ADMIN_BROADCAST_PENDING); - } - - if (policy.mInitBundle != null) { - out.startTag(null, TAG_INITIALIZATION_BUNDLE); - policy.mInitBundle.saveToXml(out); - out.endTag(null, TAG_INITIALIZATION_BUNDLE); - } - - if (policy.mPasswordTokenHandle != 0) { - out.startTag(null, TAG_PASSWORD_TOKEN_HANDLE); - out.attribute(null, ATTR_VALUE, - Long.toString(policy.mPasswordTokenHandle)); - out.endTag(null, TAG_PASSWORD_TOKEN_HANDLE); - } - - if (policy.mCurrentInputMethodSet) { - out.startTag(null, TAG_CURRENT_INPUT_METHOD_SET); - out.endTag(null, TAG_CURRENT_INPUT_METHOD_SET); - } - - for (final String cert : policy.mOwnerInstalledCaCerts) { - out.startTag(null, TAG_OWNER_INSTALLED_CA_CERT); - out.attribute(null, ATTR_ALIAS, cert); - out.endTag(null, TAG_OWNER_INSTALLED_CA_CERT); - } - - for (int i = 0, size = policy.mUserControlDisabledPackages.size(); i < size; i++) { - String packageName = policy.mUserControlDisabledPackages.get(i); - out.startTag(null, TAG_PROTECTED_PACKAGES); - out.attribute(null, ATTR_NAME, packageName); - out.endTag(null, TAG_PROTECTED_PACKAGES); - } - - if (policy.mAppsSuspended) { - out.startTag(null, TAG_APPS_SUSPENDED); - out.attribute(null, ATTR_VALUE, Boolean.toString(policy.mAppsSuspended)); - out.endTag(null, TAG_APPS_SUSPENDED); - } - - out.endTag(null, "policies"); - - out.endDocument(); - stream.flush(); - FileUtils.sync(stream); - stream.close(); - journal.commit(); + if (DevicePolicyData.store( + getUserData(userHandle), + makeJournaledFile(userHandle), + !mInjector.storageManagerIsFileBasedEncryptionEnabled())) { sendChangedNotification(userHandle); - } catch (XmlPullParserException | IOException e) { - Slog.w(LOG_TAG, "failed writing file", e); - try { - if (stream != null) { - stream.close(); - } - } catch (IOException ex) { - // Ignore - } - journal.rollback(); } } @@ -3801,225 +2455,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void loadSettingsLocked(DevicePolicyData policy, int userHandle) { - JournaledFile journal = makeJournaledFile(userHandle); - FileInputStream stream = null; - File file = journal.chooseForRead(); - boolean needsRewrite = false; - try { - stream = new FileInputStream(file); - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(stream, StandardCharsets.UTF_8.name()); - - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && type != XmlPullParser.START_TAG) { - } - String tag = parser.getName(); - if (!"policies".equals(tag)) { - throw new XmlPullParserException( - "Settings do not start with policies tag: found " + tag); - } - - // Extract the permission provider component name if available - String permissionProvider = parser.getAttributeValue(null, ATTR_PERMISSION_PROVIDER); - if (permissionProvider != null) { - policy.mRestrictionsProvider = ComponentName.unflattenFromString(permissionProvider); - } - String userSetupComplete = parser.getAttributeValue(null, ATTR_SETUP_COMPLETE); - if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) { - policy.mUserSetupComplete = true; - } - String paired = parser.getAttributeValue(null, ATTR_DEVICE_PAIRED); - if (paired != null && Boolean.toString(true).equals(paired)) { - policy.mPaired = true; - } - String deviceProvisioningConfigApplied = parser.getAttributeValue(null, - ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED); - if (deviceProvisioningConfigApplied != null - && Boolean.toString(true).equals(deviceProvisioningConfigApplied)) { - policy.mDeviceProvisioningConfigApplied = true; - } - String provisioningState = parser.getAttributeValue(null, ATTR_PROVISIONING_STATE); - if (!TextUtils.isEmpty(provisioningState)) { - policy.mUserProvisioningState = Integer.parseInt(provisioningState); - } - String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY); - if (!TextUtils.isEmpty(permissionPolicy)) { - policy.mPermissionPolicy = Integer.parseInt(permissionPolicy); - } - // Check for delegation compatibility with pre-O. - // TODO(edmanp) remove in P. - { - final String certDelegate = parser.getAttributeValue(null, - ATTR_DELEGATED_CERT_INSTALLER); - if (certDelegate != null) { - List<String> scopes = policy.mDelegationMap.get(certDelegate); - if (scopes == null) { - scopes = new ArrayList<>(); - policy.mDelegationMap.put(certDelegate, scopes); - } - if (!scopes.contains(DELEGATION_CERT_INSTALL)) { - scopes.add(DELEGATION_CERT_INSTALL); - needsRewrite = true; - } - } - final String appRestrictionsDelegate = parser.getAttributeValue(null, - ATTR_APPLICATION_RESTRICTIONS_MANAGER); - if (appRestrictionsDelegate != null) { - List<String> scopes = policy.mDelegationMap.get(appRestrictionsDelegate); - if (scopes == null) { - scopes = new ArrayList<>(); - policy.mDelegationMap.put(appRestrictionsDelegate, scopes); - } - if (!scopes.contains(DELEGATION_APP_RESTRICTIONS)) { - scopes.add(DELEGATION_APP_RESTRICTIONS); - needsRewrite = true; - } - } - } - - type = parser.next(); - int outerDepth = parser.getDepth(); - policy.mLockTaskPackages.clear(); - policy.mAdminList.clear(); - policy.mAdminMap.clear(); - policy.mAffiliationIds.clear(); - policy.mOwnerInstalledCaCerts.clear(); - policy.mUserControlDisabledPackages.clear(); - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - tag = parser.getName(); - if ("admin".equals(tag)) { - String name = parser.getAttributeValue(null, "name"); - try { - DeviceAdminInfo dai = findAdmin( - ComponentName.unflattenFromString(name), userHandle, - /* throwForMissingPermission= */ false); - if (VERBOSE_LOG - && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid) - != userHandle)) { - Slog.w(LOG_TAG, "findAdmin returned an incorrect uid " - + dai.getActivityInfo().applicationInfo.uid + " for user " - + userHandle); - } - if (dai != null) { - boolean shouldOverwritePolicies = - shouldOverwritePoliciesFromXml(dai.getComponent(), userHandle); - ActiveAdmin ap = new ActiveAdmin(dai, /* parent */ false); - ap.readFromXml(parser, shouldOverwritePolicies); - policy.mAdminMap.put(ap.info.getComponent(), ap); - } - } catch (RuntimeException e) { - Slog.w(LOG_TAG, "Failed loading admin " + name, e); - } - } else if ("delegation".equals(tag)) { - // Parse delegation info. - final String delegatePackage = parser.getAttributeValue(null, - "delegatePackage"); - final String scope = parser.getAttributeValue(null, "scope"); - - // Get a reference to the scopes list for the delegatePackage. - List<String> scopes = policy.mDelegationMap.get(delegatePackage); - // Or make a new list if none was found. - if (scopes == null) { - scopes = new ArrayList<>(); - policy.mDelegationMap.put(delegatePackage, scopes); - } - // Add the new scope to the list of delegatePackage if it's not already there. - if (!scopes.contains(scope)) { - scopes.add(scope); - } - } else if ("failed-password-attempts".equals(tag)) { - policy.mFailedPasswordAttempts = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("password-owner".equals(tag)) { - policy.mPasswordOwner = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) { - policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME)); - } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { - policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name")); - } else if (TAG_LOCK_TASK_FEATURES.equals(tag)) { - policy.mLockTaskFeatures = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_SECONDARY_LOCK_SCREEN.equals(tag)) { - policy.mSecondaryLockscreenEnabled = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_STATUS_BAR.equals(tag)) { - policy.mStatusBarDisabled = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_DISABLED)); - } else if (DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML.equals(tag)) { - policy.doNotAskCredentialsOnBoot = true; - } else if (TAG_AFFILIATION_ID.equals(tag)) { - policy.mAffiliationIds.add(parser.getAttributeValue(null, ATTR_ID)); - } else if (TAG_LAST_SECURITY_LOG_RETRIEVAL.equals(tag)) { - policy.mLastSecurityLogRetrievalTime = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_LAST_BUG_REPORT_REQUEST.equals(tag)) { - policy.mLastBugReportRequestTime = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_LAST_NETWORK_LOG_RETRIEVAL.equals(tag)) { - policy.mLastNetworkLogsRetrievalTime = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) { - String pending = parser.getAttributeValue(null, ATTR_VALUE); - policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); - } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) { - policy.mInitBundle = PersistableBundle.restoreFromXml(parser); - } else if ("active-password".equals(tag)) { - // Remove password metrics from saved settings, as we no longer wish to store - // these on disk - needsRewrite = true; - } else if (TAG_PASSWORD_VALIDITY.equals(tag)) { - if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) { - // This flag is only used for FDE devices - policy.mPasswordValidAtLastCheckpoint = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } - } else if (TAG_PASSWORD_TOKEN_HANDLE.equals(tag)) { - policy.mPasswordTokenHandle = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_CURRENT_INPUT_METHOD_SET.equals(tag)) { - policy.mCurrentInputMethodSet = true; - } else if (TAG_OWNER_INSTALLED_CA_CERT.equals(tag)) { - policy.mOwnerInstalledCaCerts.add(parser.getAttributeValue(null, ATTR_ALIAS)); - } else if (TAG_PROTECTED_PACKAGES.equals(tag)) { - policy.mUserControlDisabledPackages.add( - parser.getAttributeValue(null, ATTR_NAME)); - } else if (TAG_APPS_SUSPENDED.equals(tag)) { - policy.mAppsSuspended = - Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_VALUE)); - } else { - Slog.w(LOG_TAG, "Unknown tag: " + tag); - XmlUtils.skipCurrentTag(parser); - } - } - } catch (FileNotFoundException e) { - // Don't be noisy, this is normal if we haven't defined any policies. - } catch (NullPointerException | NumberFormatException | XmlPullParserException | IOException - | IndexOutOfBoundsException e) { - Slog.w(LOG_TAG, "failed parsing " + file, e); - } - try { - if (stream != null) { - stream.close(); - } - } catch (IOException e) { - // Ignore - } - - // Generate a list of admins from the admin map - policy.mAdminList.addAll(policy.mAdminMap.values()); + boolean needsRewrite = DevicePolicyData.load(policy, + !mInjector.storageManagerIsFileBasedEncryptionEnabled(), + makeJournaledFile(userHandle), + component -> findAdmin( + component, userHandle, /* throwForMissingPermission= */ false), + getOwnerComponent(userHandle)); // Might need to upgrade the file by rewriting it if (needsRewrite) { saveSettingsLocked(userHandle); } - validatePasswordOwnerLocked(policy); + policy.validatePasswordOwner(); updateMaximumTimeToLockLocked(userHandle); updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle); updateLockTaskFeaturesLocked(policy.mLockTaskFeatures, userHandle); @@ -4029,14 +2477,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private boolean shouldOverwritePoliciesFromXml( - ComponentName deviceAdminComponent, int userHandle) { - // http://b/123415062: If DA, overwrite with the stored policies that were agreed by the - // user to prevent apps from sneaking additional policies into updates. - return !isProfileOwner(deviceAdminComponent, userHandle) - && !isDeviceOwner(deviceAdminComponent, userHandle); - } - private void updateLockTaskPackagesLocked(List<String> packages, int userId) { long ident = mInjector.binderClearCallingIdentity(); try { @@ -4098,23 +2538,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { + Integer.toHexString(quality)); } - void validatePasswordOwnerLocked(DevicePolicyData policy) { - if (policy.mPasswordOwner >= 0) { - boolean haveOwner = false; - for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { - if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) { - haveOwner = true; - break; - } - } - if (!haveOwner) { - Slog.w(LOG_TAG, "Previous password owner " + policy.mPasswordOwner - + " no longer active; disabling"); - policy.mPasswordOwner = -1; - } - } - } - @VisibleForTesting @Override void systemReady(int phase) { @@ -5842,8 +4265,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private void setDoNotAskCredentialsOnBoot() { synchronized (getLockObject()) { DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM); - if (!policyData.doNotAskCredentialsOnBoot) { - policyData.doNotAskCredentialsOnBoot = true; + if (!policyData.mDoNotAskCredentialsOnBoot) { + policyData.mDoNotAskCredentialsOnBoot = true; saveSettingsLocked(UserHandle.USER_SYSTEM); } } @@ -5855,7 +4278,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { android.Manifest.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT, null); synchronized (getLockObject()) { DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM); - return policyData.doNotAskCredentialsOnBoot; + return policyData.mDoNotAskCredentialsOnBoot; } } @@ -14363,7 +12786,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); policy.mAdminList.remove(admin); policy.mAdminMap.remove(adminReceiver); - validatePasswordOwnerLocked(policy); + policy.validatePasswordOwner(); if (doProxyCleanup) { resetGlobalProxyLocked(policy); } diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index a5f0d045948c..f7082a9a1a0c 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -23,7 +23,6 @@ #include <android-base/properties.h> #include <android-base/stringprintf.h> #include <binder/AppOpsManager.h> -#include <binder/Nullable.h> #include <binder/Status.h> #include <sys/stat.h> #include <uuid/uuid.h> @@ -1404,7 +1403,7 @@ void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderPara } FileSystemControlParcel fsControlParcel; - fsControlParcel.incremental = aidl::make_nullable<IncrementalFileSystemControlParcel>(); + fsControlParcel.incremental = std::make_optional<IncrementalFileSystemControlParcel>(); fsControlParcel.incremental->cmd.reset(dup(ifs.control.cmd())); fsControlParcel.incremental->pendingReads.reset(dup(ifs.control.pendingReads())); fsControlParcel.incremental->log.reset(dup(ifs.control.logs())); diff --git a/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java index 27a116c8043e..1586a33ba0e9 100644 --- a/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java +++ b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java @@ -34,7 +34,8 @@ public final class SystemCaptionsManagerService extends context, com.android.internal.R.string.config_defaultSystemCaptionsManagerService), /*disallowProperty=*/ null, - /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_EAGER); + /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_EAGER + | PACKAGE_RESTART_POLICY_REFRESH_EAGER); } @Override diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java index 1cb004a6dc1e..fdcadf3e3088 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java @@ -25,6 +25,7 @@ import static android.location.Criteria.ACCURACY_COARSE; import static android.location.Criteria.ACCURACY_FINE; import static android.location.Criteria.POWER_HIGH; import static android.location.LocationManager.PASSIVE_PROVIDER; +import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF; import static androidx.test.ext.truth.location.LocationSubject.assertThat; @@ -907,6 +908,21 @@ public class LocationProviderManagerTest { assertThat(mProvider.getRequest().interval).isEqualTo(5); } + @Test + public void testProviderRequest_BatterySaver_ScreenOnOff() { + mInjector.getLocationPowerSaveModeHelper().setLocationPowerSaveMode( + LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF); + + ILocationListener listener = createMockLocationListener(); + LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false); + mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener); + + assertThat(mProvider.getRequest().reportLocation).isTrue(); + + mInjector.getScreenInteractiveHelper().setScreenInteractive(false); + assertThat(mProvider.getRequest().reportLocation).isFalse(); + } + private ILocationListener createMockLocationListener() { return spy(new ILocationListener.Stub() { @Override diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-whitelist-format.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-allowlist-format.xml index 597600303acb..597600303acb 100644 --- a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-whitelist-format.xml +++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-allowlist-format.xml diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-off.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-allowlisted-restrict-background-off.xml index 196ca28192e4..196ca28192e4 100644 --- a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-off.xml +++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-allowlisted-restrict-background-off.xml diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-on.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-allowlisted-restrict-background-on.xml index 4b7724c05d8d..4b7724c05d8d 100644 --- a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-on.xml +++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-allowlisted-restrict-background-on.xml diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-off.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-denylisted-restrict-background-off.xml index 5b1c03ce170e..5b1c03ce170e 100644 --- a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-off.xml +++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-denylisted-restrict-background-off.xml diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-on.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-denylisted-restrict-background-on.xml index bec2371cff6f..bec2371cff6f 100644 --- a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-on.xml +++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-denylisted-restrict-background-on.xml diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java index 7d6d90c4578c..02d10e3b6ce1 100644 --- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java @@ -21,7 +21,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; @@ -310,7 +309,7 @@ public class VibratorServiceTest { verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_CLICK), eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), - any(VibratorService.Vibration.class), eq(false)); + any(VibratorService.Vibration.class)); } @Test @@ -387,21 +386,26 @@ public class VibratorServiceTest { } @Test - public void vibrate_withOneShotAndNativeCallbackNotTriggered_finishesVibrationViaFallback() { + public void vibrate_withPrebakedAndNativeCallbackTriggered_finishesVibration() { + when(mNativeWrapperMock.vibratorGetSupportedEffects()) + .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK}); + doAnswer(invocation -> { + ((VibratorService.Vibration) invocation.getArgument(2)).onComplete(); + return 10_000L; // 10s + }).when(mNativeWrapperMock).vibratorPerformEffect( + anyLong(), anyLong(), any(VibratorService.Vibration.class)); VibratorService service = createService(); Mockito.clearInvocations(mNativeWrapperMock); - vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE)); - - verify(mNativeWrapperMock).vibratorOff(); - verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class)); - Mockito.clearInvocations(mNativeWrapperMock); - - // Run the scheduled callback to finish one-shot vibration. - mTestLooper.moveTimeForward(200); - mTestLooper.dispatchAll(); + vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); - verify(mNativeWrapperMock).vibratorOff(); + InOrder inOrderVerifier = inOrder(mNativeWrapperMock); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); + inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformEffect( + eq((long) VibrationEffect.EFFECT_CLICK), + eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), + any(VibratorService.Vibration.class)); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); } @Test @@ -447,30 +451,6 @@ public class VibratorServiceTest { } @Test - public void vibrate_withComposedAndNativeCallbackNotTriggered_finishesVibrationViaFallback() { - mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); - VibratorService service = createService(); - Mockito.clearInvocations(mNativeWrapperMock); - - VibrationEffect effect = VibrationEffect.startComposition() - .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10) - .compose(); - vibrate(service, effect); - - verify(mNativeWrapperMock).vibratorOff(); - verify(mNativeWrapperMock).vibratorPerformComposedEffect( - any(VibrationEffect.Composition.PrimitiveEffect[].class), - any(VibratorService.Vibration.class)); - Mockito.clearInvocations(mNativeWrapperMock); - - // Run the scheduled callback to finish one-shot vibration. - mTestLooper.moveTimeForward(10000); // 10s - mTestLooper.dispatchAll(); - - verify(mNativeWrapperMock).vibratorOff(); - } - - @Test public void vibrate_whenBinderDies_cancelsVibration() { mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); doAnswer(invocation -> { @@ -574,15 +554,15 @@ public class VibratorServiceTest { verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_CLICK), - eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), any(), anyBoolean()); + eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), any()); verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_TICK), - eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), any(), anyBoolean()); + eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), any()); verify(mNativeWrapperMock).vibratorPerformEffect( eq((long) VibrationEffect.EFFECT_DOUBLE_CLICK), - eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), any(), anyBoolean()); + eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), any()); verify(mNativeWrapperMock, never()).vibratorPerformEffect( - eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), any(), anyBoolean()); + eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), any()); } @Test diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 9a465a91e84e..8fc228734f37 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -1604,7 +1604,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setApplicationRestrictionsManagingPackage(admin1, RESTRICTIONS_DELEGATE); // DPMS correctly stores and retrieves the delegates - DevicePolicyManagerService.DevicePolicyData policy = dpms.mUserData.get(userHandle); + DevicePolicyData policy = dpms.mUserData.get(userHandle); assertEquals(2, policy.mDelegationMap.size()); MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(CERT_DELEGATE), DELEGATION_CERT_INSTALL); @@ -1846,11 +1846,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { reset(getServices().userManagerInternal); } - private DevicePolicyManagerService.ActiveAdmin getDeviceOwner() { + private ActiveAdmin getDeviceOwner() { ComponentName component = dpms.mOwners.getDeviceOwnerComponent(); - DevicePolicyManagerService.DevicePolicyData policy = + DevicePolicyData policy = dpms.getUserData(dpms.mOwners.getDeviceOwnerUserId()); - for (DevicePolicyManagerService.ActiveAdmin admin : policy.mAdminList) { + for (ActiveAdmin admin : policy.mAdminList) { if (component.equals(admin.info.getComponent())) { return admin; } @@ -3745,8 +3745,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { setUserSetupCompleteForUser(false, userId); // GIVEN userComplete is true in DPM - DevicePolicyManagerService.DevicePolicyData userData = - new DevicePolicyManagerService.DevicePolicyData(userId); + DevicePolicyData userData = new DevicePolicyData(userId); userData.mUserSetupComplete = true; dpms.mUserData.put(UserHandle.USER_SYSTEM, userData); @@ -3770,8 +3769,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { setUserSetupCompleteForUser(false, userId); // GIVEN userComplete is true in DPM - DevicePolicyManagerService.DevicePolicyData userData = - new DevicePolicyManagerService.DevicePolicyData(userId); + DevicePolicyData userData = new DevicePolicyData(userId); userData.mUserSetupComplete = true; dpms.mUserData.put(UserHandle.USER_SYSTEM, userData); diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java index e4c9cc3c05d9..1d914ec083fa 100644 --- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java @@ -88,36 +88,36 @@ public class InputMethodUtilsTest { public void testVoiceImes() throws Exception { // locale: en_US assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US, - "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); + "FakeDefaultEnKeyboardIme", "FakeDefaultAutoVoiceIme"); assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US, - "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0", - "DummyNonDefaultAutoVoiceIme1"); + "FakeDefaultEnKeyboardIme", "FakeNonDefaultAutoVoiceIme0", + "FakeNonDefaultAutoVoiceIme1"); assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); // locale: en_GB assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB, - "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); + "FakeDefaultEnKeyboardIme", "FakeDefaultAutoVoiceIme"); assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB, - "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0", - "DummyNonDefaultAutoVoiceIme1"); + "FakeDefaultEnKeyboardIme", "FakeNonDefaultAutoVoiceIme0", + "FakeNonDefaultAutoVoiceIme1"); assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); // locale: ja_JP assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP, - "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); + "FakeDefaultEnKeyboardIme", "FakeDefaultAutoVoiceIme"); assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP, - "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0", - "DummyNonDefaultAutoVoiceIme1"); + "FakeDefaultEnKeyboardIme", "FakeNonDefaultAutoVoiceIme0", + "FakeNonDefaultAutoVoiceIme1"); assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); } @Test @@ -189,67 +189,67 @@ public class InputMethodUtilsTest { @Test public void testGetImplicitlyApplicableSubtypesLocked() throws Exception { - final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US", + final InputMethodSubtype nonAutoEnUS = createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB", + final InputMethodSubtype nonAutoEnGB = createFakeInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoEnIN = createDummyInputMethodSubtype("en_IN", + final InputMethodSubtype nonAutoEnIN = createFakeInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA", + final InputMethodSubtype nonAutoFrCA = createFakeInputMethodSubtype("fr_CA", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoFr = createDummyInputMethodSubtype("fr_CA", + final InputMethodSubtype nonAutoFr = createFakeInputMethodSubtype("fr_CA", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil", + final InputMethodSubtype nonAutoFil = createFakeInputMethodSubtype("fil", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in", + final InputMethodSubtype nonAutoIn = createFakeInputMethodSubtype("in", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id", + final InputMethodSubtype nonAutoId = createFakeInputMethodSubtype("id", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype autoSubtype = createDummyInputMethodSubtype("auto", + final InputMethodSubtype autoSubtype = createFakeInputMethodSubtype("auto", SUBTYPE_MODE_KEYBOARD, !IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoJa = createDummyInputMethodSubtype("ja", + final InputMethodSubtype nonAutoJa = createFakeInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoHi = createDummyInputMethodSubtype("hi", + final InputMethodSubtype nonAutoHi = createFakeInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoSrCyrl = createDummyInputMethodSubtype("sr", + final InputMethodSubtype nonAutoSrCyrl = createFakeInputMethodSubtype("sr", "sr-Cyrl", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoSrLatn = createDummyInputMethodSubtype("sr_ZZ", + final InputMethodSubtype nonAutoSrLatn = createFakeInputMethodSubtype("sr_ZZ", "sr-Latn", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoHandwritingEn = createDummyInputMethodSubtype("en", + final InputMethodSubtype nonAutoHandwritingEn = createFakeInputMethodSubtype("en", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoHandwritingFr = createDummyInputMethodSubtype("fr", + final InputMethodSubtype nonAutoHandwritingFr = createFakeInputMethodSubtype("fr", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoHandwritingSrCyrl = createDummyInputMethodSubtype("sr", + final InputMethodSubtype nonAutoHandwritingSrCyrl = createFakeInputMethodSubtype("sr", "sr-Cyrl", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoHandwritingSrLatn = createDummyInputMethodSubtype("sr_ZZ", + final InputMethodSubtype nonAutoHandwritingSrLatn = createFakeInputMethodSubtype("sr_ZZ", "sr-Latn", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype = - createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + createFakeInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2 = - createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + createFakeInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); @@ -266,9 +266,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -290,9 +290,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -314,9 +314,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -339,9 +339,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -360,9 +360,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -382,9 +382,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -404,9 +404,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -421,9 +421,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -438,9 +438,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnUS); subtypes.add(nonAutoHi); subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -460,9 +460,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -480,9 +480,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -506,9 +506,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -533,9 +533,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoEnUS); subtypes.add(nonAutoFil); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -551,9 +551,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoJa); subtypes.add(nonAutoEnUS); subtypes.add(nonAutoFil); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -567,9 +567,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoIn); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -581,9 +581,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoIn); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -595,9 +595,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoId); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -609,9 +609,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoId); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -631,9 +631,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoFil); subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype); subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -649,22 +649,22 @@ public class InputMethodUtilsTest { @Test public void testContainsSubtypeOf() throws Exception { - final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US", + final InputMethodSubtype nonAutoEnUS = createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB", + final InputMethodSubtype nonAutoEnGB = createFakeInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil", + final InputMethodSubtype nonAutoFil = createFakeInputMethodSubtype("fil", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoFilPH = createDummyInputMethodSubtype("fil_PH", + final InputMethodSubtype nonAutoFilPH = createFakeInputMethodSubtype("fil_PH", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in", + final InputMethodSubtype nonAutoIn = createFakeInputMethodSubtype("in", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id", + final InputMethodSubtype nonAutoId = createFakeInputMethodSubtype("id", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); @@ -673,9 +673,9 @@ public class InputMethodUtilsTest { { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, !CHECK_COUNTRY, @@ -705,9 +705,9 @@ public class InputMethodUtilsTest { { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoFil); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY, SUBTYPE_MODE_KEYBOARD)); @@ -732,9 +732,9 @@ public class InputMethodUtilsTest { { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoFilPH); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY, SUBTYPE_MODE_KEYBOARD)); @@ -760,9 +760,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoIn); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY, SUBTYPE_MODE_KEYBOARD)); @@ -779,9 +779,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoId); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY, SUBTYPE_MODE_KEYBOARD)); @@ -866,7 +866,7 @@ public class InputMethodUtilsTest { assertEquals(expected.hashCode(), actual.hashCode()); } - private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name, + private static InputMethodInfo createFakeInputMethodInfo(String packageName, String name, CharSequence label, boolean isAuxIme, boolean isDefault, List<InputMethodSubtype> subtypes) { final ResolveInfo ri = new ResolveInfo(); @@ -885,15 +885,15 @@ public class InputMethodUtilsTest { return new InputMethodInfo(ri, isAuxIme, "", subtypes, 1, isDefault); } - private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode, + private static InputMethodSubtype createFakeInputMethodSubtype(String locale, String mode, boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) { - return createDummyInputMethodSubtype(locale, null /* languageTag */, mode, isAuxiliary, + return createFakeInputMethodSubtype(locale, null /* languageTag */, mode, isAuxiliary, overridesImplicitlyEnabledSubtype, isAsciiCapable, isEnabledWhenDefaultIsNotAsciiCapable); } - private static InputMethodSubtype createDummyInputMethodSubtype(String locale, + private static InputMethodSubtype createFakeInputMethodSubtype(String locale, String languageTag, String mode, boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) { @@ -920,14 +920,14 @@ public class InputMethodUtilsTest { ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>(); { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultAutoVoiceIme", - "dummy.voice0", "DummyVoice0", IS_AUX, IS_DEFAULT, subtypes)); + preinstalledImes.add(createFakeInputMethodInfo("FakeDefaultAutoVoiceIme", + "fake.voice0", "FakeVoice0", IS_AUX, IS_DEFAULT, subtypes)); } preinstalledImes.addAll(getImesWithoutDefaultVoiceIme()); return preinstalledImes; @@ -937,41 +937,41 @@ public class InputMethodUtilsTest { ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>(); { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0", - "dummy.voice1", "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes)); + preinstalledImes.add(createFakeInputMethodInfo("FakeNonDefaultAutoVoiceIme0", + "fake.voice1", "FakeVoice1", IS_AUX, !IS_DEFAULT, subtypes)); } { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1", - "dummy.voice2", "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes)); + preinstalledImes.add(createFakeInputMethodInfo("FakeNonDefaultAutoVoiceIme1", + "fake.voice2", "FakeVoice2", IS_AUX, !IS_DEFAULT, subtypes)); } { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultVoiceIme2", - "dummy.voice3", "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes)); + preinstalledImes.add(createFakeInputMethodInfo("FakeNonDefaultVoiceIme2", + "fake.voice3", "FakeVoice3", IS_AUX, !IS_DEFAULT, subtypes)); } { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultEnKeyboardIme", - "dummy.keyboard0", "DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes)); + preinstalledImes.add(createFakeInputMethodInfo("FakeDefaultEnKeyboardIme", + "fake.keyboard0", "FakeKeyboard0", !IS_AUX, IS_DEFAULT, subtypes)); } return preinstalledImes; } @@ -991,91 +991,91 @@ public class InputMethodUtilsTest { private static ArrayList<InputMethodInfo> getSamplePreinstalledImes(final String localeString) { ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>(); - // a dummy Voice IME + // a fake Voice IME { final boolean isDefaultIme = false; final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("", SUBTYPE_MODE_VOICE, IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.voice", - "com.android.inputmethod.voice", "DummyVoiceIme", IS_AUX, isDefaultIme, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.voice", + "com.android.inputmethod.voice", "FakeVoiceIme", IS_AUX, isDefaultIme, subtypes)); } - // a dummy Hindi IME + // a fake Hindi IME { final boolean isDefaultIme = contains(new String[]{ "hi", "en-rIN" }, localeString); final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); // TODO: This subtype should be marked as IS_ASCII_CAPABLE - subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.hindi", - "com.android.inputmethod.hindi", "DummyHindiIme", !IS_AUX, isDefaultIme, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.hindi", + "com.android.inputmethod.hindi", "FakeHindiIme", !IS_AUX, isDefaultIme, subtypes)); } - // a dummy Pinyin IME + // a fake Pinyin IME { final boolean isDefaultIme = contains(new String[]{ "zh-rCN" }, localeString); final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.pinyin", - "com.android.apps.inputmethod.pinyin", "DummyPinyinIme", !IS_AUX, isDefaultIme, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.pinyin", + "com.android.apps.inputmethod.pinyin", "FakePinyinIme", !IS_AUX, isDefaultIme, subtypes)); } - // a dummy Korean IME + // a fake Korean IME { final boolean isDefaultIme = contains(new String[]{ "ko" }, localeString); final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.korean", - "com.android.apps.inputmethod.korean", "DummyKoreanIme", !IS_AUX, isDefaultIme, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.korean", + "com.android.apps.inputmethod.korean", "FakeKoreanIme", !IS_AUX, isDefaultIme, subtypes)); } - // a dummy Latin IME + // a fake Latin IME { final boolean isDefaultIme = contains( new String[]{ "en-rUS", "en-rGB", "en-rIN", "en", "hi" }, localeString); final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, isDefaultIme, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.latin", + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, isDefaultIme, subtypes)); } - // a dummy Japanese IME + // a fake Japanese IME { final boolean isDefaultIme = contains(new String[]{ "ja", "ja-rJP" }, localeString); final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("emoji", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("emoji", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.japanese", - "com.android.apps.inputmethod.japanese", "DummyJapaneseIme", !IS_AUX, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.japanese", + "com.android.apps.inputmethod.japanese", "FakeJapaneseIme", !IS_AUX, isDefaultIme, subtypes)); } diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 128177b073b0..58b71d4b702a 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -462,7 +462,7 @@ public class NetworkPolicyManagerServiceTest { @Test public void testTurnRestrictBackgroundOn() throws Exception { - assertRestrictBackgroundOff(); // Sanity check. + assertRestrictBackgroundOff(); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); setRestrictBackground(true); assertRestrictBackgroundChangedReceived(futureIntent, null); @@ -471,7 +471,7 @@ public class NetworkPolicyManagerServiceTest { @Test @NetPolicyXml("restrict-background-on.xml") public void testTurnRestrictBackgroundOff() throws Exception { - assertRestrictBackgroundOn(); // Sanity check. + assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); setRestrictBackground(false); @@ -479,28 +479,27 @@ public class NetworkPolicyManagerServiceTest { } /** - * Adds whitelist when restrict background is on - app should receive an intent. + * Adds allowlist when restrict background is on - app should receive an intent. */ @Test @NetPolicyXml("restrict-background-on.xml") - public void testAddRestrictBackgroundWhitelist_restrictBackgroundOn() throws Exception { - assertRestrictBackgroundOn(); // Sanity check. + public void testAddRestrictBackgroundAllowlist_restrictBackgroundOn() throws Exception { + assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - addRestrictBackgroundWhitelist(true); + addRestrictBackgroundAllowlist(true); } /** - * Adds whitelist when restrict background is off - app should not receive an intent. + * Adds allowlist when restrict background is off - app should not receive an intent. */ @Test - public void testAddRestrictBackgroundWhitelist_restrictBackgroundOff() throws Exception { - assertRestrictBackgroundOff(); // Sanity check. - addRestrictBackgroundWhitelist(false); + public void testAddRestrictBackgroundAllowlist_restrictBackgroundOff() throws Exception { + assertRestrictBackgroundOff(); + addRestrictBackgroundAllowlist(false); } - private void addRestrictBackgroundWhitelist(boolean expectIntent) throws Exception { - // Sanity checks. - assertWhitelistUids(); + private void addRestrictBackgroundAllowlist(boolean expectIntent) throws Exception { + assertAllowlistUids(); assertUidPolicy(UID_A, POLICY_NONE); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); @@ -508,7 +507,7 @@ public class NetworkPolicyManagerServiceTest { mService.setUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); - assertWhitelistUids(UID_A); + assertAllowlistUids(UID_A); assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); mPolicyListener.waitAndVerify() .onUidPoliciesChanged(APP_ID_A, POLICY_ALLOW_METERED_BACKGROUND); @@ -520,24 +519,24 @@ public class NetworkPolicyManagerServiceTest { } /** - * Removes whitelist when restrict background is on - app should receive an intent. + * Removes allowlist when restrict background is on - app should receive an intent. */ @Test - @NetPolicyXml("uidA-whitelisted-restrict-background-on.xml") - public void testRemoveRestrictBackgroundWhitelist_restrictBackgroundOn() throws Exception { - assertRestrictBackgroundOn(); // Sanity check. + @NetPolicyXml("uidA-allowlisted-restrict-background-on.xml") + public void testRemoveRestrictBackgroundAllowlist_restrictBackgroundOn() throws Exception { + assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - removeRestrictBackgroundWhitelist(true); + removeRestrictBackgroundAllowlist(true); } /** - * Removes whitelist when restrict background is off - app should not receive an intent. + * Removes allowlist when restrict background is off - app should not receive an intent. */ @Test - @NetPolicyXml("uidA-whitelisted-restrict-background-off.xml") - public void testRemoveRestrictBackgroundWhitelist_restrictBackgroundOff() throws Exception { - assertRestrictBackgroundOff(); // Sanity check. - removeRestrictBackgroundWhitelist(false); + @NetPolicyXml("uidA-allowlisted-restrict-background-off.xml") + public void testRemoveRestrictBackgroundAllowlist_restrictBackgroundOff() throws Exception { + assertRestrictBackgroundOff(); + removeRestrictBackgroundAllowlist(false); } @Test @@ -688,9 +687,8 @@ public class NetworkPolicyManagerServiceTest { assertFalse(mService.getRestrictBackground()); } - private void removeRestrictBackgroundWhitelist(boolean expectIntent) throws Exception { - // Sanity checks. - assertWhitelistUids(UID_A); + private void removeRestrictBackgroundAllowlist(boolean expectIntent) throws Exception { + assertAllowlistUids(UID_A); assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); @@ -698,7 +696,7 @@ public class NetworkPolicyManagerServiceTest { mService.setUidPolicy(UID_A, POLICY_NONE); - assertWhitelistUids(); + assertAllowlistUids(); assertUidPolicy(UID_A, POLICY_NONE); mPolicyListener.waitAndVerify().onUidPoliciesChanged(APP_ID_A, POLICY_NONE); if (expectIntent) { @@ -709,27 +707,27 @@ public class NetworkPolicyManagerServiceTest { } /** - * Adds blacklist when restrict background is on - app should not receive an intent. + * Adds denylist when restrict background is on - app should not receive an intent. */ @Test @NetPolicyXml("restrict-background-on.xml") - public void testAddRestrictBackgroundBlacklist_restrictBackgroundOn() throws Exception { - assertRestrictBackgroundOn(); // Sanity check. + public void testAddRestrictBackgroundDenylist_restrictBackgroundOn() throws Exception { + assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - addRestrictBackgroundBlacklist(false); + addRestrictBackgroundDenylist(false); } /** - * Adds blacklist when restrict background is off - app should receive an intent. + * Adds denylist when restrict background is off - app should receive an intent. */ @Test - public void testAddRestrictBackgroundBlacklist_restrictBackgroundOff() throws Exception { - assertRestrictBackgroundOff(); // Sanity check. - addRestrictBackgroundBlacklist(true); + public void testAddRestrictBackgroundDenylist_restrictBackgroundOff() throws Exception { + assertRestrictBackgroundOff(); + addRestrictBackgroundDenylist(true); } - private void addRestrictBackgroundBlacklist(boolean expectIntent) throws Exception { - assertUidPolicy(UID_A, POLICY_NONE); // Sanity check. + private void addRestrictBackgroundDenylist(boolean expectIntent) throws Exception { + assertUidPolicy(UID_A, POLICY_NONE); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); mPolicyListener.expect().onUidPoliciesChanged(anyInt(), anyInt()); @@ -746,28 +744,28 @@ public class NetworkPolicyManagerServiceTest { } /** - * Removes blacklist when restrict background is on - app should not receive an intent. + * Removes denylist when restrict background is on - app should not receive an intent. */ @Test - @NetPolicyXml("uidA-blacklisted-restrict-background-on.xml") - public void testRemoveRestrictBackgroundBlacklist_restrictBackgroundOn() throws Exception { - assertRestrictBackgroundOn(); // Sanity check. + @NetPolicyXml("uidA-denylisted-restrict-background-on.xml") + public void testRemoveRestrictBackgroundDenylist_restrictBackgroundOn() throws Exception { + assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - removeRestrictBackgroundBlacklist(false); + removeRestrictBackgroundDenylist(false); } /** - * Removes blacklist when restrict background is off - app should receive an intent. + * Removes denylist when restrict background is off - app should receive an intent. */ @Test - @NetPolicyXml("uidA-blacklisted-restrict-background-off.xml") - public void testRemoveRestrictBackgroundBlacklist_restrictBackgroundOff() throws Exception { - assertRestrictBackgroundOff(); // Sanity check. - removeRestrictBackgroundBlacklist(true); + @NetPolicyXml("uidA-denylisted-restrict-background-off.xml") + public void testRemoveRestrictBackgroundDenylist_restrictBackgroundOff() throws Exception { + assertRestrictBackgroundOff(); + removeRestrictBackgroundDenylist(true); } - private void removeRestrictBackgroundBlacklist(boolean expectIntent) throws Exception { - assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND); // Sanity check. + private void removeRestrictBackgroundDenylist(boolean expectIntent) throws Exception { + assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); mPolicyListener.expect().onUidPoliciesChanged(anyInt(), anyInt()); @@ -784,9 +782,8 @@ public class NetworkPolicyManagerServiceTest { } @Test - @NetPolicyXml("uidA-blacklisted-restrict-background-on.xml") - public void testBlacklistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception { - // Sanity checks. + @NetPolicyXml("uidA-denylisted-restrict-background-on.xml") + public void testDenylistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception { assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND); @@ -797,12 +794,11 @@ public class NetworkPolicyManagerServiceTest { } @Test - @NetPolicyXml("uidA-whitelisted-restrict-background-on.xml") - public void testWhitelistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception { - // Sanity checks. + @NetPolicyXml("uidA-allowlisted-restrict-background-on.xml") + public void testAllowlistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception { assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - assertWhitelistUids(UID_A); + assertAllowlistUids(UID_A); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); setRestrictBackground(true); @@ -810,12 +806,11 @@ public class NetworkPolicyManagerServiceTest { } @Test - @NetPolicyXml("uidA-whitelisted-restrict-background-on.xml") - public void testWhitelistedAppIsNotifiedWhenBlacklisted() throws Exception { - // Sanity checks. + @NetPolicyXml("uidA-allowlisted-restrict-background-on.xml") + public void testAllowlistedAppIsNotifiedWhenDenylisted() throws Exception { assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - assertWhitelistUids(UID_A); + assertAllowlistUids(UID_A); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND); @@ -823,8 +818,8 @@ public class NetworkPolicyManagerServiceTest { } @Test - @NetPolicyXml("restrict-background-lists-whitelist-format.xml") - public void testRestrictBackgroundLists_whitelistFormat() throws Exception { + @NetPolicyXml("restrict-background-lists-allowlist-format.xml") + public void testRestrictBackgroundLists_allowlistFormat() throws Exception { restrictBackgroundListsTest(); } @@ -835,33 +830,33 @@ public class NetworkPolicyManagerServiceTest { } private void restrictBackgroundListsTest() throws Exception { - // UIds that are whitelisted. - assertWhitelistUids(UID_A, UID_B, UID_C); + // UIds that are allowlisted. + assertAllowlistUids(UID_A, UID_B, UID_C); assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); assertUidPolicy(UID_B, POLICY_ALLOW_METERED_BACKGROUND); assertUidPolicy(UID_C, POLICY_ALLOW_METERED_BACKGROUND); - // UIDs that are blacklisted. + // UIDs that are denylisted. assertUidPolicy(UID_D, POLICY_NONE); assertUidPolicy(UID_E, POLICY_REJECT_METERED_BACKGROUND); // UIDS that have legacy policies. assertUidPolicy(UID_F, 2); // POLICY_ALLOW_BACKGROUND_BATTERY_SAVE - // Remove whitelist. + // Remove allowlist. mService.setUidPolicy(UID_A, POLICY_NONE); assertUidPolicy(UID_A, POLICY_NONE); - assertWhitelistUids(UID_B, UID_C); + assertAllowlistUids(UID_B, UID_C); - // Add whitelist when blacklisted. + // Add allowlist when denylisted. mService.setUidPolicy(UID_E, POLICY_ALLOW_METERED_BACKGROUND); assertUidPolicy(UID_E, POLICY_ALLOW_METERED_BACKGROUND); - assertWhitelistUids(UID_B, UID_C, UID_E); + assertAllowlistUids(UID_B, UID_C, UID_E); - // Add blacklist when whitelisted. + // Add denylist when allowlisted. mService.setUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); - assertWhitelistUids(UID_C, UID_E); + assertAllowlistUids(UID_C, UID_E); } /** @@ -870,9 +865,9 @@ public class NetworkPolicyManagerServiceTest { @Test @NetPolicyXml("restrict-background-lists-mixed-format.xml") public void testRestrictBackgroundLists_mixedFormat() throws Exception { - assertWhitelistUids(UID_A, UID_C, UID_D); + assertAllowlistUids(UID_A, UID_C, UID_D); assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); - assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); // Blacklist prevails. + assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); // Denylist prevails. assertUidPolicy(UID_C, (POLICY_ALLOW_METERED_BACKGROUND | 2)); assertUidPolicy(UID_D, POLICY_ALLOW_METERED_BACKGROUND); } @@ -2045,7 +2040,7 @@ public class NetworkPolicyManagerServiceTest { } } - private void assertWhitelistUids(int... uids) { + private void assertAllowlistUids(int... uids) { assertContainsInAnyOrder(mService.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND), uids); } @@ -2133,7 +2128,6 @@ public class NetworkPolicyManagerServiceTest { private void setRestrictBackground(boolean flag) throws Exception { mService.setRestrictBackground(flag); - // Sanity check. assertEquals("restrictBackground not set", flag, mService.getRestrictBackground()); } diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java index 80f145b16147..35d6f470a504 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java @@ -48,7 +48,7 @@ public class PackageManagerServiceTest { public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras, final int flags, final String targetPkg, final IIntentReceiver finishedReceiver, final int[] userIds, - int[] instantUserIds, SparseArray<int[]> broadcastWhitelist) { + int[] instantUserIds, SparseArray<int[]> broadcastAllowList) { } public void sendPackageAddedForNewUsers(String packageName, diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt index 9f9ec31f0c91..f96ebda67602 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt @@ -23,6 +23,8 @@ import com.google.common.truth.Expect import org.junit.Rule import org.junit.Test +import org.junit.rules.Timeout +import java.util.concurrent.TimeUnit /** * Collects APKs from the device and verifies that the new parsing behavior outputs @@ -32,6 +34,9 @@ import org.junit.Test class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() { @get:Rule + val timeout = Timeout(4, TimeUnit.MINUTES) + + @get:Rule val expect = Expect.create() @Test diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java index 083df28b2278..aaa74dd832af 100644 --- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java @@ -284,28 +284,29 @@ public class ThermalManagerServiceTest { @Test public void testNotify() throws RemoteException { int status = Temperature.THROTTLING_SEVERE; + // Should only notify event not status Temperature newBattery = new Temperature(50, Temperature.TYPE_BATTERY, "batt", status); mFakeHal.mCallback.onValues(newBattery); verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).notifyThrottling(newBattery); verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) - .times(1)).onStatusChange(status); + .times(0)).onStatusChange(anyInt()); verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(0)).notifyThrottling(newBattery); verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) - .times(1)).onStatusChange(status); + .times(0)).onStatusChange(anyInt()); resetListenerMock(); - // Should only notify event not status + // Notify both event and status Temperature newSkin = new Temperature(50, Temperature.TYPE_SKIN, "skin1", status); mFakeHal.mCallback.onValues(newSkin); verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).notifyThrottling(newSkin); verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) - .times(0)).onStatusChange(anyInt()); + .times(1)).onStatusChange(status); verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).notifyThrottling(newSkin); verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) - .times(0)).onStatusChange(anyInt()); + .times(1)).onStatusChange(status); resetListenerMock(); // Back to None, should only notify event not status status = Temperature.THROTTLING_NONE; @@ -345,10 +346,13 @@ public class ThermalManagerServiceTest { @Test public void testGetCurrentStatus() throws RemoteException { - int status = Temperature.THROTTLING_EMERGENCY; + int status = Temperature.THROTTLING_SEVERE; Temperature newSkin = new Temperature(100, Temperature.TYPE_SKIN, "skin1", status); mFakeHal.mCallback.onValues(newSkin); assertEquals(status, mService.mService.getCurrentThermalStatus()); + int battStatus = Temperature.THROTTLING_EMERGENCY; + Temperature newBattery = new Temperature(60, Temperature.TYPE_BATTERY, "batt", battStatus); + assertEquals(status, mService.mService.getCurrentThermalStatus()); } @Test diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java index dcf319058ca2..e5e931115c05 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java @@ -27,6 +27,9 @@ import android.app.timezonedetector.TimeZoneCapabilities; import android.app.timezonedetector.TimeZoneConfiguration; import android.util.IndentingPrintWriter; +import java.util.ArrayList; +import java.util.List; + class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy { private StrategyListener mListener; @@ -41,6 +44,7 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy { private TelephonyTimeZoneSuggestion mLastTelephonySuggestion; private boolean mHandleAutoTimeZoneConfigChangedCalled; private boolean mDumpCalled; + private final List<Dumpable> mDumpables = new ArrayList<>(); @Override public void setStrategyListener(@NonNull StrategyListener listener) { @@ -105,7 +109,7 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy { @Override public void addDumpable(Dumpable dumpable) { - // Stubbed + mDumpables.add(dumpable); } @Override @@ -149,4 +153,8 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy { void verifyDumpCalled() { assertTrue(mDumpCalled); } + + void verifyHasDumpable(Dumpable expected) { + assertTrue(mDumpables.contains(expected)); + } } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java index 0e2c22756097..e9d57e52ce69 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java @@ -75,6 +75,16 @@ public class TimeZoneDetectorInternalImplTest { mFakeTimeZoneDetectorStrategy.verifySuggestGeolocationTimeZoneCalled(timeZoneSuggestion); } + @Test + public void testAddDumpable() throws Exception { + Dumpable stubbedDumpable = mock(Dumpable.class); + + mTimeZoneDetectorInternal.addDumpable(stubbedDumpable); + mTestHandler.assertTotalMessagesEnqueued(0); + + mFakeTimeZoneDetectorStrategy.verifyHasDumpable(stubbedDumpable); + } + private static GeolocationTimeZoneSuggestion createGeolocationTimeZoneSuggestion() { return new GeolocationTimeZoneSuggestion(ARBITRARY_ZONE_IDS); } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java index 8034cacc6923..3a1ec4f90d7a 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java @@ -52,6 +52,7 @@ import org.junit.runner.RunWith; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.Arrays; @RunWith(AndroidJUnit4.class) public class TimeZoneDetectorServiceTest { @@ -253,6 +254,39 @@ public class TimeZoneDetectorServiceTest { } @Test(expected = SecurityException.class) + public void testSuggestGeolocationTimeZone_withoutPermission() { + doThrow(new SecurityException("Mock")) + .when(mMockContext).enforceCallingOrSelfPermission(anyString(), any()); + GeolocationTimeZoneSuggestion timeZoneSuggestion = createGeolocationTimeZoneSuggestion(); + + try { + mTimeZoneDetectorService.suggestGeolocationTimeZone(timeZoneSuggestion); + fail(); + } finally { + verify(mMockContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.SET_TIME_ZONE), + anyString()); + } + } + + @Test + public void testSuggestGeolocationTimeZone() throws Exception { + doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any()); + + GeolocationTimeZoneSuggestion timeZoneSuggestion = createGeolocationTimeZoneSuggestion(); + + mTimeZoneDetectorService.suggestGeolocationTimeZone(timeZoneSuggestion); + mTestHandler.assertTotalMessagesEnqueued(1); + + verify(mMockContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.SET_TIME_ZONE), + anyString()); + + mTestHandler.waitForMessagesToBeProcessed(); + mFakeTimeZoneDetectorStrategy.verifySuggestGeolocationTimeZoneCalled(timeZoneSuggestion); + } + + @Test(expected = SecurityException.class) public void testSuggestManualTimeZone_withoutPermission() { doThrow(new SecurityException("Mock")) .when(mMockContext).enforceCallingOrSelfPermission(anyString(), any()); @@ -346,7 +380,7 @@ public class TimeZoneDetectorServiceTest { } @Test - public void testAutoTimeZoneDetectionChanged() throws Exception { + public void testHandleAutoTimeZoneConfigChanged() throws Exception { mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged(); mTestHandler.assertTotalMessagesEnqueued(1); mTestHandler.waitForMessagesToBeProcessed(); @@ -370,10 +404,15 @@ public class TimeZoneDetectorServiceTest { private static TimeZoneCapabilities createTimeZoneCapabilities() { return new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID) .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED) + .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED) .setSuggestManualTimeZone(CAPABILITY_POSSESSED) .build(); } + private static GeolocationTimeZoneSuggestion createGeolocationTimeZoneSuggestion() { + return new GeolocationTimeZoneSuggestion(Arrays.asList("TestZoneId")); + } + private static ManualTimeZoneSuggestion createManualTimeZoneSuggestion() { return new ManualTimeZoneSuggestion("TestZoneId"); } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java index 68554451e43a..a6caa4299ef6 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java @@ -41,6 +41,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.timezonedetector.ManualTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; @@ -56,10 +57,10 @@ import org.junit.Before; import org.junit.Test; import java.io.StringWriter; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; +import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; @@ -93,16 +94,26 @@ public class TimeZoneDetectorStrategyImplTest { TELEPHONY_SCORE_HIGHEST), }; - private static final TimeZoneConfiguration CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED = + private static final TimeZoneConfiguration CONFIG_AUTO_ENABLED = new TimeZoneConfiguration.Builder() .setAutoDetectionEnabled(true) .build(); - private static final TimeZoneConfiguration CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED = + private static final TimeZoneConfiguration CONFIG_AUTO_DISABLED = new TimeZoneConfiguration.Builder() .setAutoDetectionEnabled(false) .build(); + private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_DISABLED = + new TimeZoneConfiguration.Builder() + .setGeoDetectionEnabled(false) + .build(); + + private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_ENABLED = + new TimeZoneConfiguration.Builder() + .setGeoDetectionEnabled(true) + .build(); + private TimeZoneDetectorStrategyImpl mTimeZoneDetectorStrategy; private FakeCallback mFakeCallback; private MockStrategyListener mMockStrategyListener; @@ -120,7 +131,7 @@ public class TimeZoneDetectorStrategyImplTest { public void testGetCapabilities() { new Script() .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); TimeZoneCapabilities expectedCapabilities = mFakeCallback.getCapabilities(USER_ID); assertEquals(expectedCapabilities, mTimeZoneDetectorStrategy.getCapabilities(USER_ID)); } @@ -129,7 +140,7 @@ public class TimeZoneDetectorStrategyImplTest { public void testGetConfiguration() { new Script() .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); TimeZoneConfiguration expectedConfiguration = mFakeCallback.getConfiguration(USER_ID); assertTrue(expectedConfiguration.isComplete()); assertEquals(expectedConfiguration, mTimeZoneDetectorStrategy.getConfiguration(USER_ID)); @@ -140,20 +151,22 @@ public class TimeZoneDetectorStrategyImplTest { Script script = new Script(); script.initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); { // Check the fake test infra is doing what is expected. TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled()); assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone()); } script.initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED); + CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)); { // Check the fake test infra is doing what is expected. TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled()); assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone()); } } @@ -163,20 +176,22 @@ public class TimeZoneDetectorStrategyImplTest { Script script = new Script(); script.initializeUser(USER_ID, UserCase.RESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); { // Check the fake test infra is doing what is expected. TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled()); assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone()); } script.initializeUser(USER_ID, UserCase.RESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED); + CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)); { // Check the fake test infra is doing what is expected. TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled()); assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone()); } } @@ -186,20 +201,22 @@ public class TimeZoneDetectorStrategyImplTest { Script script = new Script(); script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); { // Check the fake test infra is doing what is expected. TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled()); assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone()); } script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED); + CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)); { // Check the fake test infra is doing what is expected. TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID); assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled()); + assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled()); assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone()); } } @@ -208,42 +225,61 @@ public class TimeZoneDetectorStrategyImplTest { public void testUpdateConfiguration_unrestricted() { Script script = new Script() .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); // Set the configuration with auto detection enabled. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */); // Nothing should have happened: it was initialized in this state. script.verifyConfigurationNotChanged(); // Update the configuration with auto detection disabled. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED); + script.simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */); // The settings should have been changed and the StrategyListener onChange() called. - script.verifyConfigurationChangedAndReset( - USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED); + script.verifyConfigurationChangedAndReset(USER_ID, + CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)); // Update the configuration with auto detection enabled. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */); // The settings should have been changed and the StrategyListener onChange() called. - script.verifyConfigurationChangedAndReset(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + script.verifyConfigurationChangedAndReset(USER_ID, + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); + + // Update the configuration to enable geolocation time zone detection. + script.simulateUpdateConfiguration( + USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */); + + // The settings should have been changed and the StrategyListener onChange() called. + script.verifyConfigurationChangedAndReset(USER_ID, + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)); } @Test public void testUpdateConfiguration_restricted() { Script script = new Script() .initializeUser(USER_ID, UserCase.RESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); // Try to update the configuration with auto detection disabled. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED); + script.simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */); // The settings should not have been changed: user shouldn't have the capabilities. script.verifyConfigurationNotChanged(); // Update the configuration with auto detection enabled. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + script.simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */); + + // The settings should not have been changed: user shouldn't have the capabilities. + script.verifyConfigurationNotChanged(); + + // Update the configuration to enable geolocation time zone detection. + script.simulateUpdateConfiguration( + USER_ID, CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */); // The settings should not have been changed: user shouldn't have the capabilities. script.verifyConfigurationNotChanged(); @@ -253,16 +289,18 @@ public class TimeZoneDetectorStrategyImplTest { public void testUpdateConfiguration_autoDetectNotSupported() { Script script = new Script() .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); // Try to update the configuration with auto detection disabled. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED); + script.simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */); // The settings should not have been changed: user shouldn't have the capabilities. script.verifyConfigurationNotChanged(); // Update the configuration with auto detection enabled. - script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + script.simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */); // The settings should not have been changed: user shouldn't have the capabilities. script.verifyConfigurationNotChanged(); @@ -276,7 +314,7 @@ public class TimeZoneDetectorStrategyImplTest { createEmptySlotIndex2Suggestion(); Script script = new Script() .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED) + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); script.simulateTelephonyTimeZoneSuggestion(slotIndex1TimeZoneSuggestion) @@ -308,6 +346,10 @@ public class TimeZoneDetectorStrategyImplTest { mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests()); } + /** + * Telephony suggestions have quality metadata. Ordinarily, low scoring suggestions are not + * used, but this is not true if the device's time zone setting is uninitialized. + */ @Test public void testTelephonySuggestionsWhenTimeZoneUninitialized() { assertTrue(TELEPHONY_SCORE_LOW < TELEPHONY_SCORE_USAGE_THRESHOLD); @@ -319,7 +361,7 @@ public class TimeZoneDetectorStrategyImplTest { Script script = new Script() .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); // A low quality suggestions will not be taken: The device time zone setting is left // uninitialized. @@ -376,16 +418,16 @@ public class TimeZoneDetectorStrategyImplTest { /** * Confirms that toggling the auto time zone detection setting has the expected behavior when - * the strategy is "opinionated". + * the strategy is "opinionated" when using telephony auto detection. */ @Test - public void testTogglingAutoTimeZoneDetection() { + public void testTogglingAutoDetection_autoTelephony() { Script script = new Script(); for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) { // Start with the device in a known state. script.initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED) + CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); TelephonyTimeZoneSuggestion suggestion = @@ -405,7 +447,8 @@ public class TimeZoneDetectorStrategyImplTest { mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests()); // Toggling the time zone setting on should cause the device setting to be set. - script.simulateAutoTimeZoneDetectionEnabled(USER_ID, true); + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, + true /* expectedResult */); // When time zone detection is already enabled the suggestion (if it scores highly // enough) should be set immediately. @@ -422,7 +465,8 @@ public class TimeZoneDetectorStrategyImplTest { mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests()); // Toggling the time zone setting should off should do nothing. - script.simulateAutoTimeZoneDetectionEnabled(USER_ID, false) + script.simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) .verifyTimeZoneNotChanged(); // Assert internal service state. @@ -437,7 +481,7 @@ public class TimeZoneDetectorStrategyImplTest { public void testTelephonySuggestionsSingleSlotId() { Script script = new Script() .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED) + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) { @@ -451,8 +495,7 @@ public class TimeZoneDetectorStrategyImplTest { */ // Each test case will have the same or lower score than the last. - ArrayList<TelephonyTestCase> descendingCasesByScore = - new ArrayList<>(Arrays.asList(TELEPHONY_TEST_CASES)); + List<TelephonyTestCase> descendingCasesByScore = list(TELEPHONY_TEST_CASES); Collections.reverse(descendingCasesByScore); for (TelephonyTestCase testCase : descendingCasesByScore) { @@ -504,7 +547,7 @@ public class TimeZoneDetectorStrategyImplTest { Script script = new Script() .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED) + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID) // Initialize the latest suggestions as empty so we don't need to worry about nulls // below for the first loop. @@ -583,15 +626,15 @@ public class TimeZoneDetectorStrategyImplTest { } /** - * The {@link TimeZoneDetectorStrategyImpl.Callback} is left to detect whether changing - * the time zone is actually necessary. This test proves that the service doesn't assume it - * knows the current setting. + * The {@link TimeZoneDetectorStrategyImpl.Callback} is left to detect whether changing the time + * zone is actually necessary. This test proves that the strategy doesn't assume it knows the + * current settings. */ @Test - public void testTelephonySuggestionTimeZoneDetectorStrategyDoesNotAssumeCurrentSetting() { + public void testTelephonySuggestionStrategyDoesNotAssumeCurrentSetting_autoTelephony() { Script script = new Script() .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED); + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)); TelephonyTestCase testCase = newTelephonyTestCase( MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH); @@ -609,26 +652,40 @@ public class TimeZoneDetectorStrategyImplTest { // Toggling time zone detection should set the device time zone only if the current setting // value is different from the most recent telephony suggestion. - script.simulateAutoTimeZoneDetectionEnabled(USER_ID, false) + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) .verifyTimeZoneNotChanged() - .simulateAutoTimeZoneDetectionEnabled(USER_ID, true) + .simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) .verifyTimeZoneNotChanged(); // Simulate a user turning auto detection off, a new suggestion being made while auto // detection is off, and the user turning it on again. - script.simulateAutoTimeZoneDetectionEnabled(USER_ID, false) + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) .simulateTelephonyTimeZoneSuggestion(newYorkSuggestion) .verifyTimeZoneNotChanged(); // Latest suggestion should be used. - script.simulateAutoTimeZoneDetectionEnabled(USER_ID, true) + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) .verifyTimeZoneChangedAndReset(newYorkSuggestion); } @Test - public void testManualSuggestion_unrestricted_simulateAutoTimeZoneEnabled() { + public void testManualSuggestion_autoDetectionEnabled_autoTelephony() { + checkManualSuggestion_autoDetectionEnabled(false /* geoDetectionEnabled */); + } + + @Test + public void testManualSuggestion_autoDetectionEnabled_autoGeo() { + checkManualSuggestion_autoDetectionEnabled(true /* geoDetectionEnabled */); + } + + private void checkManualSuggestion_autoDetectionEnabled(boolean geoDetectionEnabled) { + TimeZoneConfiguration geoTzEnabledConfig = + new TimeZoneConfiguration.Builder() + .setGeoDetectionEnabled(geoDetectionEnabled) + .build(); Script script = new Script() .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED) + CONFIG_AUTO_ENABLED.with(geoTzEnabledConfig)) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); // Auto time zone detection is enabled so the manual suggestion should be ignored. @@ -641,7 +698,7 @@ public class TimeZoneDetectorStrategyImplTest { public void testManualSuggestion_restricted_simulateAutoTimeZoneEnabled() { Script script = new Script() .initializeUser(USER_ID, UserCase.RESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED) + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); // Auto time zone detection is enabled so the manual suggestion should be ignored. @@ -654,7 +711,7 @@ public class TimeZoneDetectorStrategyImplTest { public void testManualSuggestion_autoDetectNotSupported_simulateAutoTimeZoneEnabled() { Script script = new Script() .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED) + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED)) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); // Auto time zone detection is enabled so the manual suggestion should be ignored. @@ -668,7 +725,7 @@ public class TimeZoneDetectorStrategyImplTest { public void testManualSuggestion_unrestricted_autoTimeZoneDetectionDisabled() { Script script = new Script() .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED) + CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); // Auto time zone detection is disabled so the manual suggestion should be used. @@ -682,7 +739,7 @@ public class TimeZoneDetectorStrategyImplTest { public void testManualSuggestion_restricted_autoTimeZoneDetectionDisabled() { Script script = new Script() .initializeUser(USER_ID, UserCase.RESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED) + CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); // Restricted users do not have the capability. @@ -696,7 +753,7 @@ public class TimeZoneDetectorStrategyImplTest { public void testManualSuggestion_autoDetectNotSupported_autoTimeZoneDetectionDisabled() { Script script = new Script() .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED) + CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); // Unrestricted users have the capability. @@ -707,10 +764,261 @@ public class TimeZoneDetectorStrategyImplTest { } @Test + public void testGeoSuggestion_uncertain() { + Script script = new Script() + .initializeUser(USER_ID, UserCase.UNRESTRICTED, + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)) + .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); + + GeolocationTimeZoneSuggestion uncertainSuggestion = createUncertainGeoLocationSuggestion(); + + script.simulateGeolocationTimeZoneSuggestion(uncertainSuggestion) + .verifyTimeZoneNotChanged(); + + // Assert internal service state. + assertEquals(uncertainSuggestion, + mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + } + + @Test + public void testGeoSuggestion_noZones() { + Script script = new Script() + .initializeUser(USER_ID, UserCase.UNRESTRICTED, + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)) + .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); + + GeolocationTimeZoneSuggestion noZonesSuggestion = createGeoLocationSuggestion(list()); + + script.simulateGeolocationTimeZoneSuggestion(noZonesSuggestion) + .verifyTimeZoneNotChanged(); + + // Assert internal service state. + assertEquals(noZonesSuggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + } + + @Test + public void testGeoSuggestion_oneZone() { + GeolocationTimeZoneSuggestion suggestion = + createGeoLocationSuggestion(list("Europe/London")); + + Script script = new Script() + .initializeUser(USER_ID, UserCase.UNRESTRICTED, + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)) + .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); + + script.simulateGeolocationTimeZoneSuggestion(suggestion) + .verifyTimeZoneChangedAndReset("Europe/London"); + + // Assert internal service state. + assertEquals(suggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + } + + /** + * In the current implementation, the first zone ID is always used unless the device is set to + * one of the other options. This is "stickiness" - the device favors the zone it is currently + * set to until that unambiguously can't be correct. + */ + @Test + public void testGeoSuggestion_multiZone() { + GeolocationTimeZoneSuggestion londonOnlySuggestion = + createGeoLocationSuggestion(list("Europe/London")); + GeolocationTimeZoneSuggestion londonOrParisSuggestion = + createGeoLocationSuggestion(list("Europe/Paris", "Europe/London")); + GeolocationTimeZoneSuggestion parisOnlySuggestion = + createGeoLocationSuggestion(list("Europe/Paris")); + + Script script = new Script() + .initializeUser(USER_ID, UserCase.UNRESTRICTED, + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)) + .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); + + script.simulateGeolocationTimeZoneSuggestion(londonOnlySuggestion) + .verifyTimeZoneChangedAndReset("Europe/London"); + assertEquals(londonOnlySuggestion, + mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + + // Confirm bias towards the current device zone when there's multiple zones to choose from. + script.simulateGeolocationTimeZoneSuggestion(londonOrParisSuggestion) + .verifyTimeZoneNotChanged(); + assertEquals(londonOrParisSuggestion, + mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + + script.simulateGeolocationTimeZoneSuggestion(parisOnlySuggestion) + .verifyTimeZoneChangedAndReset("Europe/Paris"); + assertEquals(parisOnlySuggestion, + mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + + // Now the suggestion that previously left the device on Europe/London will leave the device + // on Europe/Paris. + script.simulateGeolocationTimeZoneSuggestion(londonOrParisSuggestion) + .verifyTimeZoneNotChanged(); + assertEquals(londonOrParisSuggestion, + mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + } + + /** + * Confirms that toggling the auto time zone detection enabled setting has the expected behavior + * when the strategy is "opinionated" and "un-opinionated" when in geolocation detection is + * enabled. + */ + @Test + public void testTogglingAutoDetectionEnabled_autoGeo() { + GeolocationTimeZoneSuggestion geolocationSuggestion = + createGeoLocationSuggestion(list("Europe/London")); + GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion = + createUncertainGeoLocationSuggestion(); + ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris"); + + Script script = new Script() + .initializeUser(USER_ID, UserCase.UNRESTRICTED, + CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_ENABLED)) + .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); + + script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion); + + // When time zone detection is not enabled, the time zone suggestion will not be set. + script.verifyTimeZoneNotChanged(); + + // Assert internal service state. + assertEquals(geolocationSuggestion, + mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + + // Toggling the time zone setting on should cause the device setting to be set. + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) + .verifyTimeZoneChangedAndReset("Europe/London"); + + // Toggling the time zone setting should off should do nothing because the device is now + // set to that time zone. + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) + .verifyTimeZoneNotChanged() + .simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) + .verifyTimeZoneNotChanged(); + + // Now toggle auto time zone setting, and confirm it is opinionated. + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) + .simulateManualTimeZoneSuggestion( + USER_ID, manualSuggestion, true /* expectedResult */) + .verifyTimeZoneChangedAndReset(manualSuggestion) + .simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) + .verifyTimeZoneChangedAndReset("Europe/London"); + + // Now withdraw the geolocation suggestion, and assert the strategy is no longer + // opinionated. + /* expectedResult */ + script.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion) + .verifyTimeZoneNotChanged() + .simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) + .verifyTimeZoneNotChanged() + .simulateManualTimeZoneSuggestion( + USER_ID, manualSuggestion, true /* expectedResult */) + .verifyTimeZoneChangedAndReset(manualSuggestion) + .simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) + .verifyTimeZoneNotChanged(); + + // Assert internal service state. + assertEquals(uncertainGeolocationSuggestion, + mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + } + + /** + * Confirms that changing the geolocation time zone detection enabled setting has the expected + * behavior, i.e. immediately recompute the detected time zone using different signals. + */ + @Test + public void testChangingGeoDetectionEnabled() { + GeolocationTimeZoneSuggestion geolocationSuggestion = + createGeoLocationSuggestion(list("Europe/London")); + TelephonyTimeZoneSuggestion telephonySuggestion = createTelephonySuggestion( + SLOT_INDEX1, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE, + "Europe/Paris"); + + Script script = new Script() + .initializeUser(USER_ID, UserCase.UNRESTRICTED, + CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) + .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); + + // Add suggestions. Nothing should happen as time zone detection is disabled. + script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion) + .verifyTimeZoneNotChanged(); + script.simulateTelephonyTimeZoneSuggestion(telephonySuggestion) + .verifyTimeZoneNotChanged(); + + // Assert internal service state. + assertEquals(geolocationSuggestion, + mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion()); + assertEquals(telephonySuggestion, + mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1).suggestion); + + // Toggling the time zone detection enabled setting on should cause the device setting to be + // set from the telephony signal, as we've started with geolocation time zone detection + // disabled. + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) + .verifyTimeZoneChangedAndReset(telephonySuggestion); + + // Changing the detection to enable geo detection should cause the device tz setting to + // change to the geo suggestion. + script.simulateUpdateConfiguration( + USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */) + .verifyTimeZoneChangedAndReset(geolocationSuggestion.getZoneIds().get(0)); + + // Changing the detection to disable geo detection should cause the device tz setting to + // change to the telephony suggestion. + script.simulateUpdateConfiguration( + USER_ID, CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */) + .verifyTimeZoneChangedAndReset(telephonySuggestion); + } + + /** + * The {@link TimeZoneDetectorStrategyImpl.Callback} is left to detect whether changing the time + * zone is actually necessary. This test proves that the strategy doesn't assume it knows the + * current setting. + */ + @Test + public void testTimeZoneDetectorStrategyDoesNotAssumeCurrentSetting_autoGeo() { + GeolocationTimeZoneSuggestion losAngelesSuggestion = + createGeoLocationSuggestion(list("America/Los_Angeles")); + GeolocationTimeZoneSuggestion newYorkSuggestion = + createGeoLocationSuggestion(list("America/New_York")); + + Script script = new Script() + .initializeUser(USER_ID, UserCase.UNRESTRICTED, + CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED)); + + // Initialization. + script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion) + .verifyTimeZoneChangedAndReset("America/Los_Angeles"); + // Suggest it again - it should not be set because it is already set. + script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion) + .verifyTimeZoneNotChanged(); + + // Toggling time zone detection should set the device time zone only if the current setting + // value is different from the most recent telephony suggestion. + /* expectedResult */ + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) + .verifyTimeZoneNotChanged() + .simulateUpdateConfiguration( + USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) + .verifyTimeZoneNotChanged(); + + // Simulate a user turning auto detection off, a new suggestion being made while auto + // detection is off, and the user turning it on again. + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */) + .simulateGeolocationTimeZoneSuggestion(newYorkSuggestion) + .verifyTimeZoneNotChanged(); + // Latest suggestion should be used. + script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */) + .verifyTimeZoneChangedAndReset("America/New_York"); + } + + @Test public void testAddDumpable() { new Script() .initializeUser(USER_ID, UserCase.UNRESTRICTED, - CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED) + CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED)) .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID); AtomicBoolean dumpCalled = new AtomicBoolean(false); @@ -733,6 +1041,15 @@ public class TimeZoneDetectorStrategyImplTest { return new ManualTimeZoneSuggestion(zoneId); } + private static TelephonyTimeZoneSuggestion createTelephonySuggestion( + int slotIndex, @MatchType int matchType, @Quality int quality, String zoneId) { + return new TelephonyTimeZoneSuggestion.Builder(slotIndex) + .setMatchType(matchType) + .setQuality(quality) + .setZoneId(zoneId) + .build(); + } + private static TelephonyTimeZoneSuggestion createEmptySlotIndex1Suggestion() { return new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX1).build(); } @@ -741,6 +1058,17 @@ public class TimeZoneDetectorStrategyImplTest { return new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX2).build(); } + private static GeolocationTimeZoneSuggestion createUncertainGeoLocationSuggestion() { + return createGeoLocationSuggestion(null); + } + + private static GeolocationTimeZoneSuggestion createGeoLocationSuggestion( + @Nullable List<String> zoneIds) { + GeolocationTimeZoneSuggestion suggestion = new GeolocationTimeZoneSuggestion(zoneIds); + suggestion.addDebugInfo("Test suggestion"); + return suggestion; + } + static class FakeCallback implements TimeZoneDetectorStrategyImpl.Callback { private TimeZoneCapabilities mCapabilities; @@ -757,7 +1085,8 @@ public class TimeZoneDetectorStrategyImplTest { TimeZoneConfiguration configuration) { assertEquals(userId, capabilities.getUserId()); mCapabilities = capabilities; - assertTrue(configuration.isComplete()); + assertTrue("Configuration must be complete when initializing, config=" + configuration, + configuration.isComplete()); mConfiguration.init(new UserConfiguration(userId, configuration)); } @@ -790,11 +1119,8 @@ public class TimeZoneDetectorStrategyImplTest { mConfiguration.set(new UserConfiguration(userId, newConfig)); if (!newConfig.equals(oldConfig)) { - if (oldConfig.isAutoDetectionEnabled() != newConfig.isAutoDetectionEnabled()) { - // Simulate what happens when the auto detection enabled configuration is - // changed. - mStrategy.handleAutoTimeZoneConfigChanged(); - } + // Simulate what happens when the auto detection configuration is changed. + mStrategy.handleAutoTimeZoneConfigChanged(); } } @@ -804,6 +1130,11 @@ public class TimeZoneDetectorStrategyImplTest { } @Override + public boolean isGeoDetectionEnabled() { + return mConfiguration.getLatest().configuration.isGeoDetectionEnabled(); + } + + @Override public boolean isDeviceTimeZoneInitialized() { return mTimeZoneId.getLatest() != null; } @@ -942,32 +1273,33 @@ public class TimeZoneDetectorStrategyImplTest { * supplied configuration. */ private static TimeZoneCapabilities createCapabilities( - int userId, UserCase userRole, TimeZoneConfiguration configuration) { - switch (userRole) { + int userId, UserCase userCase, TimeZoneConfiguration configuration) { + switch (userCase) { case UNRESTRICTED: { int suggestManualTimeZoneCapability = configuration.isAutoDetectionEnabled() ? CAPABILITY_NOT_APPLICABLE : CAPABILITY_POSSESSED; return new TimeZoneCapabilities.Builder(userId) .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED) + .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED) .setSuggestManualTimeZone(suggestManualTimeZoneCapability) .build(); } case RESTRICTED: { return new TimeZoneCapabilities.Builder(userId) .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED) + .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED) .setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED) .build(); - } case AUTO_DETECT_NOT_SUPPORTED: { return new TimeZoneCapabilities.Builder(userId) .setConfigureAutoDetectionEnabled(CAPABILITY_NOT_SUPPORTED) + .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED) .setSuggestManualTimeZone(CAPABILITY_POSSESSED) .build(); - } default: - throw new AssertionError(userRole + " not recognized"); + throw new AssertionError(userCase + " not recognized"); } } @@ -978,8 +1310,8 @@ public class TimeZoneDetectorStrategyImplTest { private class Script { Script initializeUser( - @UserIdInt int userId, UserCase userRole, TimeZoneConfiguration configuration) { - TimeZoneCapabilities capabilities = createCapabilities(userId, userRole, configuration); + @UserIdInt int userId, UserCase userCase, TimeZoneConfiguration configuration) { + TimeZoneCapabilities capabilities = createCapabilities(userId, userCase, configuration); mFakeCallback.initializeUser(userId, capabilities, configuration); return this; } @@ -989,27 +1321,24 @@ public class TimeZoneDetectorStrategyImplTest { return this; } - Script simulateAutoTimeZoneDetectionEnabled(@UserIdInt int userId, boolean enabled) { - TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder() - .setAutoDetectionEnabled(enabled) - .build(); - return simulateUpdateConfiguration(userId, configuration); - } - /** - * Simulates the time zone detection strategy receiving an updated configuration. + * Simulates the time zone detection strategy receiving an updated configuration and checks + * the return value. */ Script simulateUpdateConfiguration( - @UserIdInt int userId, TimeZoneConfiguration configuration) { - mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration); + @UserIdInt int userId, TimeZoneConfiguration configuration, + boolean expectedResult) { + assertEquals(expectedResult, + mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration)); return this; } /** - * Simulates the time zone detection strategy receiving a telephony-originated suggestion. + * Simulates the time zone detection strategy receiving a geolocation-originated + * suggestion. */ - Script simulateTelephonyTimeZoneSuggestion(TelephonyTimeZoneSuggestion timeZoneSuggestion) { - mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(timeZoneSuggestion); + Script simulateGeolocationTimeZoneSuggestion(GeolocationTimeZoneSuggestion suggestion) { + mTimeZoneDetectorStrategy.suggestGeolocationTimeZone(suggestion); return this; } @@ -1024,13 +1353,26 @@ public class TimeZoneDetectorStrategyImplTest { return this; } + /** + * Simulates the time zone detection strategy receiving a telephony-originated suggestion. + */ + Script simulateTelephonyTimeZoneSuggestion(TelephonyTimeZoneSuggestion timeZoneSuggestion) { + mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(timeZoneSuggestion); + return this; + } + + /** + * Confirms that the device's time zone has not been set by previous actions since the test + * state was last reset. + */ Script verifyTimeZoneNotChanged() { mFakeCallback.assertTimeZoneNotChanged(); return this; } - Script verifyTimeZoneChangedAndReset(TelephonyTimeZoneSuggestion suggestion) { - mFakeCallback.assertTimeZoneChangedTo(suggestion.getZoneId()); + /** Verifies the device's time zone has been set and clears change tracking history. */ + Script verifyTimeZoneChangedAndReset(String zoneId) { + mFakeCallback.assertTimeZoneChangedTo(zoneId); mFakeCallback.commitAllChanges(); return this; } @@ -1041,6 +1383,12 @@ public class TimeZoneDetectorStrategyImplTest { return this; } + Script verifyTimeZoneChangedAndReset(TelephonyTimeZoneSuggestion suggestion) { + mFakeCallback.assertTimeZoneChangedTo(suggestion.getZoneId()); + mFakeCallback.commitAllChanges(); + return this; + } + /** * Verifies that the configuration has been changed to the expected value. */ @@ -1120,4 +1468,8 @@ public class TimeZoneDetectorStrategyImplTest { mOnConfigurationChangedCalled = false; } } + + private static <T> List<T> list(T... values) { + return Arrays.asList(values); + } } 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 4dec7a1a0ab9..7c7b1a296673 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -1383,7 +1383,7 @@ public class AppStandbyControllerTests { getStandbyBucket(mController, PACKAGE_1)); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, false); - mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); + mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS); assertEquals("Unexempted sync scheduled should bring the package out of the Never bucket", STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1)); @@ -1391,7 +1391,7 @@ public class AppStandbyControllerTests { mStateChangedLatch = new CountDownLatch(1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, false); - mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); + mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS); assertEquals("Unexempted sync scheduled should not elevate a non Never bucket", STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); } @@ -1402,7 +1402,7 @@ public class AppStandbyControllerTests { mInjector.mDeviceIdleMode = true; mStateChangedLatch = new CountDownLatch(1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true); - mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); + mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS); assertEquals("Exempted sync scheduled in doze should set bucket to working set", STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1)); @@ -1410,7 +1410,7 @@ public class AppStandbyControllerTests { mInjector.mDeviceIdleMode = false; mStateChangedLatch = new CountDownLatch(1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true); - mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); + mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS); assertEquals("Exempted sync scheduled while not in doze should set bucket to active", STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); } diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java deleted file mode 100644 index f6c854e23494..000000000000 --- a/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.server.slice; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper.RunWithLooper; - -import androidx.test.filters.SmallTest; - -import com.android.server.UiServiceTestCase; -import com.android.server.slice.SliceManagerService.PackageMatchingCache; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.function.Supplier; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@RunWithLooper -public class PackageMatchingCacheTest extends UiServiceTestCase { - - private final Supplier<String> supplier = mock(Supplier.class); - private final PackageMatchingCache cache = new PackageMatchingCache(supplier); - - @Test - public void testNulls() { - // Doesn't get for a null input - cache.matches(null); - verify(supplier, never()).get(); - - // Gets once valid input in sent. - cache.matches(""); - verify(supplier).get(); - } - - @Test - public void testCaching() { - when(supplier.get()).thenReturn("ret.pkg"); - - assertTrue(cache.matches("ret.pkg")); - assertTrue(cache.matches("ret.pkg")); - assertTrue(cache.matches("ret.pkg")); - - verify(supplier, times(1)).get(); - } - - @Test - public void testGetOnFailure() { - when(supplier.get()).thenReturn("ret.pkg"); - assertTrue(cache.matches("ret.pkg")); - - when(supplier.get()).thenReturn("other.pkg"); - assertTrue(cache.matches("other.pkg")); - verify(supplier, times(2)).get(); - } -} diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java index a4436951f48b..cf1c36c0d243 100644 --- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java @@ -90,8 +90,6 @@ public class SliceManagerServiceTest extends UiServiceTestCase { @Test public void testAddPinCreatesPinned() throws RemoteException { - doReturn("pkg").when(mService).getDefaultHome(anyInt()); - mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken); mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken); verify(mService, times(1)).createPinnedSlice(eq(maybeAddUserId(TEST_URI, 0)), anyString()); @@ -99,8 +97,6 @@ public class SliceManagerServiceTest extends UiServiceTestCase { @Test public void testRemovePinDestroysPinned() throws RemoteException { - doReturn("pkg").when(mService).getDefaultHome(anyInt()); - mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken); when(mCreatedSliceState.unpin(eq("pkg"), eq(mToken))).thenReturn(false); diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp index b3d75d31cb60..4ca5b9e4b14f 100644 --- a/services/tests/wmtests/Android.bp +++ b/services/tests/wmtests/Android.bp @@ -2,15 +2,37 @@ // Build WmTests package //######################################################################## +// Include all test java files. +filegroup { + name: "wmtests-sources", + srcs: [ + "src/**/*.java", + ], +} + +genrule { + name: "wmtests.protologsrc", + srcs: [ + ":protolog-groups", + ":wmtests-sources", + ], + tools: ["protologtool"], + cmd: "$(location protologtool) transform-protolog-calls " + + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " + + "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " + + "--loggroups-class com.android.internal.protolog.ProtoLogGroup " + + "--loggroups-jar $(location :protolog-groups) " + + "--output-srcjar $(out) " + + "$(locations :wmtests-sources)", + out: ["wmtests.protolog.srcjar"], +} + android_test { name: "WmTests", // We only want this apk build for tests. - - // Include all test java files. - srcs: [ - "src/**/*.java", - ], + srcs: [":wmtests.protologsrc"], static_libs: [ "frameworks-base-testutils", diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 6061f13fcee5..f860e174fd15 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -1506,7 +1506,7 @@ public class ActivityRecordTests extends WindowTestsBase { final WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT; - final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState( + final TestWindowState w = new TestWindowState( mAtm.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity); mActivity.addWindow(w); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index 2e988af29638..567610018fc1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -225,5 +225,27 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { mockSession.finishMocking(); } + + @Test + public void testResumeNextActivityOnCrashedAppDied() { + mSupervisor.beginDeferResume(); + final ActivityRecord homeActivity = new ActivityBuilder(mAtm) + .setTask(mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()) + .build(); + final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); + mSupervisor.endDeferResume(); + // Assume the activity is finishing and hidden because it was crashed. + activity.finishing = true; + activity.mVisibleRequested = false; + activity.setVisible(false); + activity.getRootTask().mPausingActivity = activity; + homeActivity.setState(Task.ActivityState.PAUSED, "test"); + + // Even the visibility states are invisible, the next activity should be resumed because + // the crashed activity was pausing. + mAtm.mInternal.handleAppDied(activity.app, false /* restarting */, + null /* finishInstrumentationCallback */); + assertEquals(Task.ActivityState.RESUMED, homeActivity.getState()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 7adceade0b9b..1b2192035213 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -133,10 +133,10 @@ public class AppTransitionControllerTest extends WindowTestsBase { // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (opening, visible) // +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, invisible) final Task stack1 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1); + final ActivityRecord activity1 = createTestActivityRecord(stack1); final Task stack2 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2); + final ActivityRecord activity2 = createTestActivityRecord(stack2); activity2.setVisible(false); activity2.mVisibleRequested = false; @@ -162,13 +162,13 @@ public class AppTransitionControllerTest extends WindowTestsBase { // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (closing, invisible) // +- [TaskStack2] - [Task2] - [ActivityRecord2] (opening, visible) final Task stack1 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1); + final ActivityRecord activity1 = createTestActivityRecord(stack1); activity1.setVisible(true); activity1.mVisibleRequested = true; activity1.mRequestForceTransition = true; final Task stack2 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2); + final ActivityRecord activity2 = createTestActivityRecord(stack2); activity2.setVisible(false); activity2.mVisibleRequested = false; activity2.mRequestForceTransition = true; @@ -193,10 +193,10 @@ public class AppTransitionControllerTest extends WindowTestsBase { @Test public void testGetAnimationTargets_exitingBeforeTransition() { // Create another non-empty task so the animation target won't promote to task display area. - WindowTestUtils.createTestActivityRecord( + createTestActivityRecord( mDisplayContent.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()); final Task stack = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(stack); + final ActivityRecord activity = createTestActivityRecord(stack); activity.setVisible(false); activity.mIsExiting = true; @@ -218,20 +218,20 @@ public class AppTransitionControllerTest extends WindowTestsBase { // +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, invisible) // +- [AppWindow2] (being-replaced) final Task stack1 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1); + final ActivityRecord activity1 = createTestActivityRecord(stack1); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); attrs.setTitle("AppWindow1"); - final WindowTestUtils.TestWindowState appWindow1 = createWindowState(attrs, activity1); + final TestWindowState appWindow1 = createWindowState(attrs, activity1); appWindow1.mWillReplaceWindow = true; activity1.addWindow(appWindow1); final Task stack2 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2); + final ActivityRecord activity2 = createTestActivityRecord(stack2); activity2.setVisible(false); activity2.mVisibleRequested = false; attrs.setTitle("AppWindow2"); - final WindowTestUtils.TestWindowState appWindow2 = createWindowState(attrs, activity2); + final TestWindowState appWindow2 = createWindowState(attrs, activity2); appWindow2.mWillReplaceWindow = true; activity2.addWindow(appWindow2); @@ -262,21 +262,17 @@ public class AppTransitionControllerTest extends WindowTestsBase { // +- [ActivityRecord4] (invisible) final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack1, 0 /* userId */); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1); activity1.setVisible(false); activity1.mVisibleRequested = true; - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task1); activity2.setVisible(false); activity2.mVisibleRequested = false; final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskInStack(stack2, 0 /* userId */); - final ActivityRecord activity3 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); - final ActivityRecord activity4 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task2); + final ActivityRecord activity4 = createActivityRecordInTask(mDisplayContent, task2); activity4.setVisible(false); activity4.mVisibleRequested = false; @@ -303,12 +299,10 @@ public class AppTransitionControllerTest extends WindowTestsBase { // +- [ActivityRecord2] (closing, visible) final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task); activity1.setVisible(false); activity1.mVisibleRequested = true; - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task); final ArraySet<ActivityRecord> opening = new ArraySet<>(); opening.add(activity1); @@ -337,22 +331,18 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack1, 0 /* userId */); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1); activity1.setVisible(false); activity1.mVisibleRequested = true; activity1.setOccludesParent(false); - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task1); final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskInStack(stack2, 0 /* userId */); - final ActivityRecord activity3 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task2); activity3.setOccludesParent(false); - final ActivityRecord activity4 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity4 = createActivityRecordInTask(mDisplayContent, task2); final ArraySet<ActivityRecord> opening = new ArraySet<>(); opening.add(activity1); @@ -381,24 +371,20 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack1, 0 /* userId */); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1); activity1.setVisible(false); activity1.mVisibleRequested = true; activity1.setOccludesParent(false); - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task1); activity2.setVisible(false); activity2.mVisibleRequested = true; final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskInStack(stack2, 0 /* userId */); - final ActivityRecord activity3 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task2); activity3.setOccludesParent(false); - final ActivityRecord activity4 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity4 = createActivityRecordInTask(mDisplayContent, task2); final ArraySet<ActivityRecord> opening = new ArraySet<>(); opening.add(activity1); @@ -425,13 +411,11 @@ public class AppTransitionControllerTest extends WindowTestsBase { // +- [Task2] - [ActivityRecord2] (closing, visible) final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1); activity1.setVisible(false); activity1.mVisibleRequested = true; final Task task2 = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task2); final ArraySet<ActivityRecord> opening = new ArraySet<>(); opening.add(activity1); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 17914e7fb68c..ee030af36b8f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -151,8 +151,7 @@ public class AppTransitionTests extends WindowTestsBase { final Task stack1 = createTaskStackOnDisplay(dc1); final Task task1 = createTaskInStack(stack1, 0 /* userId */); - final ActivityRecord activity1 = - WindowTestUtils.createTestActivityRecord(dc1); + final ActivityRecord activity1 = createTestActivityRecord(dc1); task1.addChild(activity1, 0); // Simulate same app is during opening / closing transition set stage. diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 888935ef9747..085b8dec2cb7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -92,7 +92,7 @@ public class AppWindowTokenTests extends WindowTestsBase { public void setUp() throws Exception { mStack = createTaskStackOnDisplay(mDisplayContent); mTask = createTaskInStack(mStack, 0 /* userId */); - mActivity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + mActivity = createTestActivityRecord(mDisplayContent); mTask.addChild(mActivity, 0); } @@ -165,7 +165,7 @@ public class AppWindowTokenTests extends WindowTestsBase { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); attrs.setTitle("AppWindow"); - final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mActivity); + final TestWindowState appWindow = createWindowState(attrs, mActivity); mActivity.addWindow(appWindow); // Set initial orientation and update. @@ -198,7 +198,7 @@ public class AppWindowTokenTests extends WindowTestsBase { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); attrs.setTitle("RotationByPolicy"); - final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mActivity); + final TestWindowState appWindow = createWindowState(attrs, mActivity); mActivity.addWindow(appWindow); // Set initial orientation and update. @@ -244,7 +244,7 @@ public class AppWindowTokenTests extends WindowTestsBase { TYPE_BASE_APPLICATION); attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD; attrs.setTitle("AppWindow"); - final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mActivity); + final TestWindowState appWindow = createWindowState(attrs, mActivity); // Add window with show when locked flag mActivity.addWindow(appWindow); @@ -307,7 +307,7 @@ public class AppWindowTokenTests extends WindowTestsBase { assertEquals(Configuration.ORIENTATION_PORTRAIT, displayConfig.orientation); assertEquals(Configuration.ORIENTATION_PORTRAIT, activityConfig.orientation); - final ActivityRecord topActivity = WindowTestUtils.createTestActivityRecord(mStack); + final ActivityRecord topActivity = createTestActivityRecord(mStack); topActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); assertEquals(Configuration.ORIENTATION_LANDSCAPE, displayConfig.orientation); @@ -490,8 +490,7 @@ public class AppWindowTokenTests extends WindowTestsBase { } private ActivityRecord createTestActivityRecordForGivenTask(Task task) { - final ActivityRecord activity = - WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); task.addChild(activity, 0); waitUntilHandlersIdle(); return activity; @@ -562,7 +561,7 @@ public class AppWindowTokenTests extends WindowTestsBase { public void testHasStartingWindow() { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING); - final WindowTestUtils.TestWindowState startingWindow = createWindowState(attrs, mActivity); + final TestWindowState startingWindow = createWindowState(attrs, mActivity); mActivity.startingDisplayed = true; mActivity.addWindow(startingWindow); assertTrue("Starting window should be present", mActivity.hasStartingWindow()); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 0cc61599c2ac..d54b4a0a72f6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -326,7 +326,7 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals(dc, stack.getDisplayContent()); final Task task = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(dc); + final ActivityRecord activity = createTestActivityRecord(dc); task.addChild(activity, 0); assertEquals(dc, task.getDisplayContent()); assertEquals(dc, activity.getDisplayContent()); @@ -397,16 +397,14 @@ public class DisplayContentTests extends WindowTestsBase { // Add stack with activity. final Task stack0 = createTaskStackOnDisplay(dc0); final Task task0 = createTaskInStack(stack0, 0 /* userId */); - final ActivityRecord activity = - WindowTestUtils.createTestActivityRecord(dc0); + final ActivityRecord activity = createTestActivityRecord(dc0); task0.addChild(activity, 0); dc0.configureDisplayPolicy(); assertNotNull(dc0.mTapDetector); final Task stack1 = createTaskStackOnDisplay(dc1); final Task task1 = createTaskInStack(stack1, 0 /* userId */); - final ActivityRecord activity1 = - WindowTestUtils.createTestActivityRecord(dc0); + final ActivityRecord activity1 = createTestActivityRecord(dc0); task1.addChild(activity1, 0); dc1.configureDisplayPolicy(); assertNotNull(dc1.mTapDetector); @@ -1296,7 +1294,7 @@ public class DisplayContentTests extends WindowTestsBase { final ActivityRecord pinnedActivity = createActivityRecord(displayContent, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); final Task pinnedTask = pinnedActivity.getRootTask(); - final ActivityRecord homeActivity = WindowTestUtils.createTestActivityRecord( + final ActivityRecord homeActivity = createTestActivityRecord( displayContent.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()); if (displayConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { homeActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index 4ea5b97decf4..0675c6d04422 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -48,12 +48,14 @@ import static android.view.WindowManagerPolicyConstants.ALT_BAR_LEFT; import static android.view.WindowManagerPolicyConstants.ALT_BAR_RIGHT; import static android.view.WindowManagerPolicyConstants.ALT_BAR_TOP; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; @@ -874,6 +876,19 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { } @Test + public void testFixedRotationInsetsSourceFrame() { + mDisplayPolicy.beginLayoutLw(mFrames, mDisplayContent.getConfiguration().uiMode); + doReturn((mDisplayContent.getRotation() + 1) % 4).when(mDisplayContent) + .rotationForActivityInDifferentOrientation(eq(mWindow.mActivityRecord)); + final Rect frame = mWindow.getInsetsState().getSource(ITYPE_STATUS_BAR).getFrame(); + mDisplayContent.rotateInDifferentOrientationIfNeeded(mWindow.mActivityRecord); + final Rect rotatedFrame = mWindow.getInsetsState().getSource(ITYPE_STATUS_BAR).getFrame(); + + assertEquals(DISPLAY_WIDTH, frame.width()); + assertEquals(DISPLAY_HEIGHT, rotatedFrame.width()); + } + + @Test public void testScreenDecorWindows() { final WindowState decorWindow = spy( createWindow(null, TYPE_APPLICATION_OVERLAY, "decorWindow")); diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index e18d93d82686..45369975fcc5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -95,8 +95,7 @@ public class DragDropControllerTests extends WindowTestsBase { * Creates a window state which can be used as a drop target. */ private WindowState createDropTargetWindow(String name, int ownerId) { - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord( - mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); final Task stack = createTaskStackOnDisplay( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent); final Task task = createTaskInStack(stack, ownerId); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 5e83e66536ed..085230d35c6a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -28,6 +28,9 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -40,6 +43,7 @@ import static org.mockito.Mockito.verify; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; +import android.util.IntArray; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.test.InsetsModeSession; @@ -328,6 +332,27 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertNull(getController().getControlsForDispatch(app)); } + @Test + public void testTransientVisibilityOfFixedRotationState() { + final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final InsetsSourceProvider provider = getController().getSourceProvider(ITYPE_STATUS_BAR); + provider.setWindow(statusBar, null, null); + + final InsetsState rotatedState = new InsetsState(app.getInsetsState(), + true /* copySources */); + spyOn(app.mToken); + doReturn(rotatedState).when(app.mToken).getFixedRotationTransformInsetsState(); + assertTrue(rotatedState.getSource(ITYPE_STATUS_BAR).isVisible()); + + provider.getSource().setVisible(false); + mDisplayContent.getInsetsPolicy().showTransient( + IntArray.wrap(new int[] { ITYPE_STATUS_BAR })); + + assertTrue(mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR)); + assertFalse(app.getInsetsState().getSource(ITYPE_STATUS_BAR).isVisible()); + } + private InsetsStateController getController() { return mDisplayContent.getInsetsStateController(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java index d1510cf811fb..8223024234fb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java @@ -25,9 +25,12 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import com.android.server.protolog.ProtoLogImpl; +import com.android.internal.protolog.ProtoLogGroup; +import com.android.internal.protolog.ProtoLogImpl; +import com.android.internal.protolog.common.ProtoLog; import org.junit.After; +import org.junit.Ignore; import org.junit.Test; /** @@ -35,6 +38,7 @@ import org.junit.Test; */ @SmallTest @Presubmit +@Ignore("b/163095037") public class ProtoLogIntegrationTest { @After public void tearDown() { @@ -44,17 +48,21 @@ public class ProtoLogIntegrationTest { @Test public void testProtoLogToolIntegration() { ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class); - runWith(mockedProtoLog, () -> { - ProtoLogGroup.testProtoLog(); - }); + runWith(mockedProtoLog, this::testProtoLog); verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.ERROR), eq(ProtoLogGroup.TEST_GROUP), anyInt(), eq(0b0010101001010111), - eq(ProtoLogGroup.TEST_GROUP.isLogToLogcat() + eq(com.android.internal.protolog.ProtoLogGroup.TEST_GROUP.isLogToLogcat() ? "Test completed successfully: %b %d %o %x %e %g %f %% %s" : null), eq(new Object[]{true, 1L, 2L, 3L, 0.4, 0.5, 0.6, "ok"})); } + private void testProtoLog() { + ProtoLog.e(ProtoLogGroup.TEST_GROUP, + "Test completed successfully: %b %d %o %x %e %g %f %% %s.", + true, 1, 2, 3, 0.4, 0.5, 0.6, "ok"); + } + /** * Starts protolog for the duration of {@code runnable}, with a ProtoLogImpl instance installed. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 0e1d4dc4aa0d..982e469cba92 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -568,7 +568,9 @@ public class SizeCompatTests extends WindowTestsBase { private static WindowState addWindowToActivity(ActivityRecord activity) { final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; - final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState( + params.setFitInsetsSides(0); + params.setFitInsetsTypes(0); + final TestWindowState w = new TestWindowState( activity.mWmService, mock(Session.class), new TestIWindow(), params, activity); WindowTestsBase.makeWindowVisible(w); w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; @@ -581,7 +583,7 @@ public class SizeCompatTests extends WindowTestsBase { doReturn(true).when(displayPolicy).hasStatusBar(); displayPolicy.onConfigurationChanged(); - final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken( + final TestWindowToken token = createTestWindowToken( WindowManager.LayoutParams.TYPE_STATUS_BAR, displayContent); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_STATUS_BAR); @@ -589,7 +591,7 @@ public class SizeCompatTests extends WindowTestsBase { attrs.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; attrs.setFitInsetsTypes(0 /* types */); - final WindowTestUtils.TestWindowState statusBar = new WindowTestUtils.TestWindowState( + final TestWindowState statusBar = new TestWindowState( displayContent.mWmService, mock(Session.class), new TestIWindow(), attrs, token); token.addWindow(statusBar); statusBar.setRequestedSize(displayContent.mBaseDisplayWidth, diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java index 3492556b3682..260f1e9a9259 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -76,8 +76,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { // Stack should contain visible app window to be considered visible. final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */); assertFalse(mPinnedStack.isVisible()); - final ActivityRecord pinnedApp = - WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord pinnedApp = createTestActivityRecord(mDisplayContent); pinnedTask.addChild(pinnedApp, 0 /* addPos */); assertTrue(mPinnedStack.isVisible()); } @@ -92,7 +91,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { final Task stack = createTaskStackOnDisplay( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); task.addChild(activity, 0 /* addPos */); final TaskDisplayArea taskDisplayArea = activity.getDisplayArea(); activity.mNeedsAnimationBoundsLayer = true; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java index 205b842253b7..7cf30c0c9f35 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java @@ -85,14 +85,12 @@ public class TaskStackTests extends WindowTestsBase { public void testClosingAppDifferentStackOrientation() { final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); - ActivityRecord activity1 = - WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity1 = createTestActivityRecord(mDisplayContent); task1.addChild(activity1, 0); activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); final Task task2 = createTaskInStack(stack, 1 /* userId */); - ActivityRecord activity2= - WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity2 = createTestActivityRecord(mDisplayContent); task2.addChild(activity2, 0); activity2.setOrientation(SCREEN_ORIENTATION_PORTRAIT); @@ -105,14 +103,12 @@ public class TaskStackTests extends WindowTestsBase { public void testMoveTaskToBackDifferentStackOrientation() { final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); - ActivityRecord activity1 = - WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity1 = createTestActivityRecord(mDisplayContent); task1.addChild(activity1, 0); activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); final Task task2 = createTaskInStack(stack, 1 /* userId */); - ActivityRecord activity2 = - WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity2 = createTestActivityRecord(mDisplayContent); task2.addChild(activity2, 0); activity2.setOrientation(SCREEN_ORIENTATION_PORTRAIT); assertEquals(SCREEN_ORIENTATION_PORTRAIT, stack.getOrientation()); @@ -221,7 +217,7 @@ public class TaskStackTests extends WindowTestsBase { public void testActivityAndTaskGetsProperType() { final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); - ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity1 = createTestActivityRecord(mDisplayContent); // First activity should become standard task1.addChild(activity1, 0); @@ -229,7 +225,7 @@ public class TaskStackTests extends WindowTestsBase { assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType()); // Second activity should also become standard - ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity2 = createTestActivityRecord(mDisplayContent); task1.addChild(activity2, WindowContainer.POSITION_TOP); assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, activity2.getActivityType()); assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType()); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 92b6e6ef8ec9..ace0400bc293 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -56,8 +56,7 @@ public class TaskTests extends WindowTestsBase { public void testRemoveContainer() { final Task stackController1 = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stackController1, 0 /* userId */); - final ActivityRecord activity = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity = createActivityRecordInTask(mDisplayContent, task); task.removeIfPossible(); // Assert that the container was removed. @@ -70,8 +69,7 @@ public class TaskTests extends WindowTestsBase { public void testRemoveContainer_deferRemoval() { final Task stackController1 = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stackController1, 0 /* userId */); - final ActivityRecord activity = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity = createActivityRecordInTask(mDisplayContent, task); doReturn(true).when(task).shouldDeferRemoval(); @@ -153,10 +151,8 @@ public class TaskTests extends WindowTestsBase { public void testIsInStack() { final Task task1 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity1 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task1); - final ActivityRecord activity2 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task2); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task2); assertEquals(activity1, task1.isInTask(activity1)); assertNull(task1.isInTask(activity2)); } @@ -165,12 +161,9 @@ public class TaskTests extends WindowTestsBase { public void testRemoveChildForOverlayTask() { final Task task = createTaskStackOnDisplay(mDisplayContent); final int taskId = task.mTaskId; - final ActivityRecord activity1 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); - final ActivityRecord activity2 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); - final ActivityRecord activity3 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task); activity1.setTaskOverlay(true); activity2.setTaskOverlay(true); activity3.setTaskOverlay(true); diff --git a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java index 75ed928b08a0..6ed762283524 100644 --- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java @@ -44,7 +44,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testFlow() { - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity); mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(activity); mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(activity); @@ -56,8 +56,8 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testMultiple() { - final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(mDisplayContent); - final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity1 = createTestActivityRecord(mDisplayContent); + final ActivityRecord activity2 = createTestActivityRecord(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity1); mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(activity1); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity2); @@ -72,7 +72,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testClear() { - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity); mDisplayContent.mUnknownAppVisibilityController.clear(); assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved()); @@ -80,7 +80,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testRemoveFinishingInvisibleActivityFromUnknown() { - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity); activity.finishing = true; activity.mVisibleRequested = true; @@ -90,7 +90,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testAppRemoved() { - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity); mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(activity); assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index 8ac44f2afcfd..4163a9a546a0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -810,8 +810,7 @@ public class WindowContainerTests extends WindowTestsBase { public void testOnDisplayChanged() { final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity = createActivityRecordInTask(mDisplayContent, task); final DisplayContent newDc = createNewDisplay(); stack.getDisplayArea().removeStack(stack); @@ -854,19 +853,17 @@ public class WindowContainerTests extends WindowTestsBase { public void testTaskCanApplyAnimation() { final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity2 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); - final ActivityRecord activity1 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task); verifyWindowContainerApplyAnimation(task, activity1, activity2); } @Test public void testStackCanApplyAnimation() { final Task stack = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask(mDisplayContent, + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, createTaskInStack(stack, 0 /* userId */)); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask(mDisplayContent, + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, createTaskInStack(stack, 0 /* userId */)); verifyWindowContainerApplyAnimation(stack, activity1, activity2); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 8cfa4f00c8b6..91352972e772 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -931,8 +931,7 @@ public class WindowOrganizerTests extends WindowTestsBase { final Task stack = createStack(); final Task task = createTask(stack); - final ActivityRecord record = WindowTestUtils.createActivityRecordInTask( - stack.mDisplayContent, task); + final ActivityRecord record = createActivityRecordInTask(stack.mDisplayContent, task); stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription")); @@ -966,8 +965,7 @@ public class WindowOrganizerTests extends WindowTestsBase { public void testInterceptBackPressedOnTaskRoot() throws RemoteException { final Task stack = createStack(); final Task task = createTask(stack); - final ActivityRecord activity = WindowTestUtils.createActivityRecordInTask( - stack.mDisplayContent, task); + final ActivityRecord activity = createActivityRecordInTask(stack.mDisplayContent, task); final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW); // Setup the task to be controlled by the MW mode organizer diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java index 2f736555ae1b..189e540af0ca 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.Display.INVALID_DISPLAY; @@ -253,6 +255,19 @@ public class WindowProcessControllerTests extends WindowTestsBase { assertFalse(mWpc.registeredForActivityConfigChanges()); } + @Test + public void testProcessLevelConfiguration() { + Configuration config = new Configuration(); + config.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME); + mWpc.onRequestedOverrideConfigurationChanged(config); + assertEquals(ACTIVITY_TYPE_HOME, config.windowConfiguration.getActivityType()); + assertEquals(ACTIVITY_TYPE_UNDEFINED, mWpc.getActivityType()); + + mWpc.onMergedOverrideConfigurationChanged(config); + assertEquals(ACTIVITY_TYPE_HOME, config.windowConfiguration.getActivityType()); + assertEquals(ACTIVITY_TYPE_UNDEFINED, mWpc.getActivityType()); + } + private TestDisplayContent createTestDisplayContentInContainer() { return new TestDisplayContent.Builder(mAtm, 1000, 1500).build(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 3894a2eaa461..f095fd42900b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -357,8 +357,7 @@ public class WindowStateTests extends WindowTestsBase { // Call prepareWindowToDisplayDuringRelayout for a windows that are not children of an // activity. Both windows have the FLAG_TURNS_SCREEN_ON so both should call wakeup - final WindowToken windowToken = WindowTestUtils.createTestWindowToken(FIRST_SUB_WINDOW, - mDisplayContent); + final WindowToken windowToken = createTestWindowToken(FIRST_SUB_WINDOW, mDisplayContent); final WindowState firstWindow = createWindow(null, TYPE_APPLICATION, windowToken, "firstWindow"); final WindowState secondWindow = createWindow(null, TYPE_APPLICATION, windowToken, diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java deleted file mode 100644 index 0180d87290a1..000000000000 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ /dev/null @@ -1,134 +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 com.android.server.wm; - -import static android.app.AppOpsManager.OP_NONE; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.server.wm.WindowContainer.POSITION_TOP; - -import android.os.IBinder; -import android.view.IWindow; -import android.view.WindowManager; - -import com.android.server.wm.WindowTestsBase.ActivityBuilder; - -/** - * A collection of static functions that provide access to WindowManager related test functionality. - */ -class WindowTestUtils { - - /** Creates a {@link Task} and adds it to the specified {@link Task}. */ - static Task createTaskInStack(WindowManagerService service, Task stack, int userId) { - final Task task = new WindowTestsBase.TaskBuilder(stack.mStackSupervisor) - .setUserId(userId) - .setStack(stack) - .build(); - return task; - } - - /** Creates an {@link ActivityRecord} and adds it to the specified {@link Task}. */ - static ActivityRecord createActivityRecordInTask(DisplayContent dc, Task task) { - final ActivityRecord activity = createTestActivityRecord(dc); - task.addChild(activity, POSITION_TOP); - return activity; - } - - static ActivityRecord createTestActivityRecord(Task stack) { - final ActivityRecord activity = new ActivityBuilder(stack.mAtmService) - .setStack(stack) - .setCreateTask(true) - .build(); - postCreateActivitySetup(activity, stack.getDisplayContent()); - return activity; - } - - static ActivityRecord createTestActivityRecord(DisplayContent dc) { - final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService).build(); - postCreateActivitySetup(activity, dc); - return activity; - } - - private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) { - activity.onDisplayChanged(dc); - activity.setOccludesParent(true); - activity.setVisible(true); - activity.mVisibleRequested = true; - } - - static TestWindowToken createTestWindowToken(int type, DisplayContent dc) { - return createTestWindowToken(type, dc, false /* persistOnEmpty */); - } - - static TestWindowToken createTestWindowToken(int type, DisplayContent dc, - boolean persistOnEmpty) { - SystemServicesTestRule.checkHoldsLock(dc.mWmService.mGlobalLock); - - return new TestWindowToken(type, dc, persistOnEmpty); - } - - /* Used so we can gain access to some protected members of the {@link WindowToken} class */ - static class TestWindowToken extends WindowToken { - - private TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) { - super(dc.mWmService, mock(IBinder.class), type, persistOnEmpty, dc, - false /* ownerCanManageAppTokens */); - } - - int getWindowsCount() { - return mChildren.size(); - } - - boolean hasWindow(WindowState w) { - return mChildren.contains(w); - } - } - - /** Used to track resize reports. */ - static class TestWindowState extends WindowState { - boolean mResizeReported; - - TestWindowState(WindowManagerService service, Session session, IWindow window, - WindowManager.LayoutParams attrs, WindowToken token) { - super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, 0, - false /* ownerCanAddInternalSystemWindow */); - } - - @Override - void reportResized() { - super.reportResized(); - mResizeReported = true; - } - - @Override - public boolean isGoneForLayoutLw() { - return false; - } - - @Override - void updateResizingWindowIfNeeded() { - // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive - // the system that it can actually update the window. - boolean hadSurface = mHasSurface; - mHasSurface = true; - - super.updateResizingWindowIfNeeded(); - - mHasSurface = hadSurface; - } - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index ec19a58b17c4..5ce61b4e4916 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -47,6 +47,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; +import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -66,6 +67,7 @@ import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.os.Build; import android.os.Bundle; +import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; @@ -239,7 +241,7 @@ class WindowTestsBase extends SystemServiceTestsBase { private WindowToken createWindowToken( DisplayContent dc, int windowingMode, int activityType, int type) { if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) { - return WindowTestUtils.createTestWindowToken(type, dc); + return createTestWindowToken(type, dc); } return createActivityRecord(dc, windowingMode, activityType); @@ -249,10 +251,39 @@ class WindowTestsBase extends SystemServiceTestsBase { return createTestActivityRecord(dc, windowingMode, activityType); } - ActivityRecord createTestActivityRecord(DisplayContent dc, int - windowingMode, int activityType) { + ActivityRecord createTestActivityRecord(DisplayContent dc, int windowingMode, + int activityType) { final Task stack = createTaskStackOnDisplay(windowingMode, activityType, dc); - return WindowTestUtils.createTestActivityRecord(stack); + return createTestActivityRecord(stack); + } + + /** Creates an {@link ActivityRecord} and adds it to the specified {@link Task}. */ + static ActivityRecord createActivityRecordInTask(DisplayContent dc, Task task) { + final ActivityRecord activity = createTestActivityRecord(dc); + task.addChild(activity, POSITION_TOP); + return activity; + } + + static ActivityRecord createTestActivityRecord(DisplayContent dc) { + final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService).build(); + postCreateActivitySetup(activity, dc); + return activity; + } + + static ActivityRecord createTestActivityRecord(Task stack) { + final ActivityRecord activity = new ActivityBuilder(stack.mAtmService) + .setStack(stack) + .setCreateTask(true) + .build(); + postCreateActivitySetup(activity, stack.getDisplayContent()); + return activity; + } + + private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) { + activity.onDisplayChanged(dc); + activity.setOccludesParent(true); + activity.setVisible(true); + activity.mVisibleRequested = true; } WindowState createWindow(WindowState parent, int type, String name) { @@ -274,8 +305,7 @@ class WindowTestsBase extends SystemServiceTestsBase { } WindowState createAppWindow(Task task, int type, String name) { - final ActivityRecord activity = - WindowTestUtils.createTestActivityRecord(task.getDisplayContent()); + final ActivityRecord activity = createTestActivityRecord(task.getDisplayContent()); task.addChild(activity, 0); return createWindow(null, type, activity, name); } @@ -390,7 +420,11 @@ class WindowTestsBase extends SystemServiceTestsBase { /** Creates a {@link Task} and adds it to the specified {@link Task}. */ Task createTaskInStack(Task stack, int userId) { - return WindowTestUtils.createTaskInStack(mWm, stack, userId); + final Task task = new TaskBuilder(stack.mStackSupervisor) + .setUserId(userId) + .setStack(stack) + .build(); + return task; } /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */ @@ -432,12 +466,11 @@ class WindowTestsBase extends SystemServiceTestsBase { return createNewDisplay(displayInfo, true /* supportIme */); } - /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */ - WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs, - WindowToken token) { + /** Creates a {@link TestWindowState} */ + TestWindowState createWindowState(WindowManager.LayoutParams attrs, WindowToken token) { SystemServicesTestRule.checkHoldsLock(mWm.mGlobalLock); - return new WindowTestUtils.TestWindowState(mWm, mMockSession, mIWindow, attrs, token); + return new TestWindowState(mWm, mMockSession, mIWindow, attrs, token); } /** Creates a {@link DisplayContent} as parts of simulate display info for test. */ @@ -1055,4 +1088,66 @@ class WindowTestsBase extends SystemServiceTestsBase { public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { } } + + static TestWindowToken createTestWindowToken(int type, DisplayContent dc) { + return createTestWindowToken(type, dc, false /* persistOnEmpty */); + } + + static TestWindowToken createTestWindowToken(int type, DisplayContent dc, + boolean persistOnEmpty) { + SystemServicesTestRule.checkHoldsLock(dc.mWmService.mGlobalLock); + + return new TestWindowToken(type, dc, persistOnEmpty); + } + + /** Used so we can gain access to some protected members of the {@link WindowToken} class */ + static class TestWindowToken extends WindowToken { + + private TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) { + super(dc.mWmService, mock(IBinder.class), type, persistOnEmpty, dc, + false /* ownerCanManageAppTokens */); + } + + int getWindowsCount() { + return mChildren.size(); + } + + boolean hasWindow(WindowState w) { + return mChildren.contains(w); + } + } + + /** Used to track resize reports. */ + static class TestWindowState extends WindowState { + boolean mResizeReported; + + TestWindowState(WindowManagerService service, Session session, IWindow window, + WindowManager.LayoutParams attrs, WindowToken token) { + super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, 0, + false /* ownerCanAddInternalSystemWindow */); + } + + @Override + void reportResized() { + super.reportResized(); + mResizeReported = true; + } + + @Override + public boolean isGoneForLayoutLw() { + return false; + } + + @Override + void updateResizingWindowIfNeeded() { + // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive + // the system that it can actually update the window. + boolean hadSurface = mHasSurface; + mHasSurface = true; + + super.updateResizingWindowIfNeeded(); + + mHasSurface = hadSurface; + } + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index f185da395754..e0785c13a336 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -27,6 +27,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -58,8 +59,7 @@ public class WindowTokenTests extends WindowTestsBase { @Test public void testAddWindow() { - final WindowTestUtils.TestWindowToken token = - WindowTestUtils.createTestWindowToken(0, mDisplayContent); + final TestWindowToken token = createTestWindowToken(0, mDisplayContent); assertEquals(0, token.getWindowsCount()); @@ -93,7 +93,7 @@ public class WindowTokenTests extends WindowTestsBase { @Test public void testChildRemoval() { final DisplayContent dc = mDisplayContent; - final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(0, dc); + final TestWindowToken token = createTestWindowToken(0, dc); assertEquals(token, dc.getWindowToken(token.token)); @@ -116,7 +116,7 @@ public class WindowTokenTests extends WindowTestsBase { */ @Test public void testTokenRemovalProcess() { - final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken( + final TestWindowToken token = createTestWindowToken( TYPE_TOAST, mDisplayContent, true /* persistOnEmpty */); // Verify that the token is on the display @@ -146,29 +146,40 @@ public class WindowTokenTests extends WindowTestsBase { assertEquals(0, token.getWindowsCount()); } - @UseTestDisplay(addWindows = { W_ACTIVITY, W_WALLPAPER }) @Test public void testFinishFixedRotationTransform() { - final WindowToken appToken = mAppWindow.mToken; - final WindowToken wallpaperToken = mWallpaperWindow.mToken; + final WindowToken[] tokens = new WindowToken[3]; + for (int i = 0; i < tokens.length; i++) { + tokens[i] = createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent); + } + final Configuration config = new Configuration(mDisplayContent.getConfiguration()); final int originalRotation = config.windowConfiguration.getRotation(); final int targetRotation = (originalRotation + 1) % 4; config.windowConfiguration.setRotation(targetRotation); - appToken.applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); - wallpaperToken.linkFixedRotationTransform(appToken); + tokens[0].applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); + tokens[1].linkFixedRotationTransform(tokens[0]); // The window tokens should apply the rotation by the transformation. - assertEquals(targetRotation, appToken.getWindowConfiguration().getRotation()); - assertEquals(targetRotation, wallpaperToken.getWindowConfiguration().getRotation()); + assertEquals(targetRotation, tokens[0].getWindowConfiguration().getRotation()); + assertEquals(targetRotation, tokens[1].getWindowConfiguration().getRotation()); + + tokens[2].applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); + // The tokens[1] was linked to tokens[0], this should make tokens[1] link to tokens[2]. + tokens[1].linkFixedRotationTransform(tokens[2]); + + // Assume the display doesn't rotate, the transformation will be canceled. + tokens[0].finishFixedRotationTransform(); - // The display doesn't rotate, the transformation will be canceled. - mAppWindow.mToken.finishFixedRotationTransform(); + // The tokens[0] should restore to the original rotation. + assertEquals(originalRotation, tokens[0].getWindowConfiguration().getRotation()); + // The tokens[1] is linked to tokens[2], it should keep the target rotation. + assertNotEquals(originalRotation, tokens[1].getWindowConfiguration().getRotation()); - // The window tokens should restore to the original rotation. - assertEquals(originalRotation, appToken.getWindowConfiguration().getRotation()); - assertEquals(originalRotation, wallpaperToken.getWindowConfiguration().getRotation()); + tokens[2].finishFixedRotationTransform(); + // The rotation of tokens[1] should be restored because its linked state is finished. + assertEquals(originalRotation, tokens[1].getWindowConfiguration().getRotation()); } /** diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 0f898f8e679e..9ff44eba8fa0 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -967,10 +967,10 @@ public class VoiceInteractionManagerService extends SystemService { throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel"); } - final int callingUid = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); final long caller = Binder.clearCallingIdentity(); try { - return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); + return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUserId, bcp47Locale); } finally { Binder.restoreCallingIdentity(caller); } @@ -1010,7 +1010,7 @@ public class VoiceInteractionManagerService extends SystemService { "Illegal argument(s) in deleteKeyphraseSoundModel"); } - final int callingUid = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); final long caller = Binder.clearCallingIdentity(); boolean deleted = false; try { @@ -1018,7 +1018,8 @@ public class VoiceInteractionManagerService extends SystemService { if (unloadStatus != SoundTriggerInternal.STATUS_OK) { Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus); } - deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); + deleted = mDbHelper.deleteKeyphraseSoundModel( + keyphraseId, callingUserId, bcp47Locale); return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR; } finally { if (deleted) { @@ -1045,11 +1046,11 @@ public class VoiceInteractionManagerService extends SystemService { throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase"); } - final int callingUid = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); final long caller = Binder.clearCallingIdentity(); try { KeyphraseSoundModel model = - mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); + mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUserId, bcp47Locale); return model != null; } finally { Binder.restoreCallingIdentity(caller); @@ -1067,11 +1068,11 @@ public class VoiceInteractionManagerService extends SystemService { throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase"); } - final int callingUid = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); final long caller = Binder.clearCallingIdentity(); try { KeyphraseSoundModel model = - mDbHelper.getKeyphraseSoundModel(keyphrase, callingUid, bcp47Locale); + mDbHelper.getKeyphraseSoundModel(keyphrase, callingUserId, bcp47Locale); if (model == null) { return null; } @@ -1118,11 +1119,11 @@ public class VoiceInteractionManagerService extends SystemService { } } - int callingUid = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); final long caller = Binder.clearCallingIdentity(); try { KeyphraseSoundModel soundModel = - mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); + mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUserId, bcp47Locale); if (soundModel == null || soundModel.getUuid() == null || soundModel.getKeyphrases() == null) { diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java index e57b03098758..d4308c4c30ad 100644 --- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -74,7 +75,7 @@ public final class CarrierAppUtils { * privileged apps may have changed. */ public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, - TelephonyManager telephonyManager, int userId, Context context) { + TelephonyManager telephonyManager, @UserIdInt int userId, Context context) { if (DEBUG) { Log.d(TAG, "disableCarrierAppsUntilPrivileged"); } @@ -101,7 +102,7 @@ public final class CarrierAppUtils { * Manager can kill it, and this can lead to crashes as the app is in an unexpected state. */ public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, - int userId, Context context) { + @UserIdInt int userId, Context context) { if (DEBUG) { Log.d(TAG, "disableCarrierAppsUntilPrivileged"); } @@ -117,9 +118,9 @@ public final class CarrierAppUtils { systemCarrierAssociatedAppsDisabledUntilUsed, context); } - private static ContentResolver getContentResolverForUser(Context context, int userId) { - Context userContext = context.createContextAsUser(UserHandle.getUserHandleForUid(userId), - 0); + private static ContentResolver getContentResolverForUser(Context context, + @UserIdInt int userId) { + Context userContext = context.createContextAsUser(UserHandle.of(userId), 0); return userContext.getContentResolver(); } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 2b2608724e12..78dc377a303c 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -46,6 +46,7 @@ import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.ISms; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.SmsRawData; +import com.android.telephony.Rlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -1953,7 +1954,6 @@ public final class SmsManager { public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, @android.telephony.SmsCbMessage.MessageFormat int ranType) { boolean success = false; - if (endMessageId < startMessageId) { throw new IllegalArgumentException("endMessageId < startMessageId"); } @@ -1962,10 +1962,14 @@ public final class SmsManager { if (iSms != null) { // If getSubscriptionId() returns INVALID or an inactive subscription, we will use // the default phone internally. - success = iSms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(), + int subId = getSubscriptionId(); + success = iSms.enableCellBroadcastRangeForSubscriber(subId, startMessageId, endMessageId, ranType); + Rlog.d(TAG, "enableCellBroadcastRange: " + (success ? "succeeded" : "failed") + + " at calling enableCellBroadcastRangeForSubscriber. subId = " + subId); } } catch (RemoteException ex) { + Rlog.d(TAG, "enableCellBroadcastRange: " + ex.getStackTrace()); // ignore it } @@ -2019,10 +2023,14 @@ public final class SmsManager { if (iSms != null) { // If getSubscriptionId() returns INVALID or an inactive subscription, we will use // the default phone internally. - success = iSms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(), + int subId = getSubscriptionId(); + success = iSms.disableCellBroadcastRangeForSubscriber(subId, startMessageId, endMessageId, ranType); + Rlog.d(TAG, "disableCellBroadcastRange: " + (success ? "succeeded" : "failed") + + " at calling disableCellBroadcastRangeForSubscriber. subId = " + subId); } } catch (RemoteException ex) { + Rlog.d(TAG, "disableCellBroadcastRange: " + ex.getStackTrace()); // ignore it } diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp index e233fed7e785..9da17db6a573 100644 --- a/tests/Internal/Android.bp +++ b/tests/Internal/Android.bp @@ -11,6 +11,7 @@ android_test { "androidx.test.rules", "mockito-target-minus-junit4", "truth-prebuilt", + "platform-test-annotations", ], java_resource_dirs: ["res"], certificate: "platform", diff --git a/services/tests/servicestests/src/com/android/server/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java index 3e9f625ecdd9..3db011683a86 100644 --- a/services/tests/servicestests/src/com/android/server/protolog/ProtoLogImplTest.java +++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java @@ -14,11 +14,11 @@ * limitations under the License. */ -package com.android.server.protolog; +package com.android.internal.protolog; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; -import static com.android.server.protolog.ProtoLogImpl.PROTOLOG_VERSION; +import static com.android.internal.protolog.ProtoLogImpl.PROTOLOG_VERSION; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -42,7 +42,7 @@ import android.util.proto.ProtoInputStream; import androidx.test.filters.SmallTest; -import com.android.server.protolog.common.IProtoLogGroup; +import com.android.internal.protolog.common.IProtoLogGroup; import org.junit.After; import org.junit.Before; diff --git a/services/tests/servicestests/src/com/android/server/protolog/ProtoLogViewerConfigReaderTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java index 02540559fbd0..ae5021638745 100644 --- a/services/tests/servicestests/src/com/android/server/protolog/ProtoLogViewerConfigReaderTest.java +++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.protolog; +package com.android.internal.protolog; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; diff --git a/services/tests/servicestests/src/com/android/server/protolog/common/LogDataTypeTest.java b/tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java index 4c7f5fdc821c..e20ca3df57c7 100644 --- a/services/tests/servicestests/src/com/android/server/protolog/common/LogDataTypeTest.java +++ b/tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.protolog.common; +package com.android.internal.protolog.common; import static org.junit.Assert.assertEquals; diff --git a/tests/RollbackTest/README.txt b/tests/RollbackTest/README.txt index c0b718a3e2c1..bc3b3bc3a1ee 100644 --- a/tests/RollbackTest/README.txt +++ b/tests/RollbackTest/README.txt @@ -9,10 +9,10 @@ StagedRollbackTest - device driven test for staged rollbacks. TestApp - - source for dummy apks used in testing. + - source for fake apks used in testing. TestApex - - source for dummy apex modules used in testing. + - source for fake apex modules used in testing. Running the tests ================= diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp index 530d0e492f2e..76f8df02465b 100644 --- a/tests/StagedInstallTest/Android.bp +++ b/tests/StagedInstallTest/Android.bp @@ -18,6 +18,9 @@ android_test_helper_app { srcs: ["app/src/**/*.java"], static_libs: ["androidx.test.rules", "cts-install-lib"], test_suites: ["general-tests"], + java_resources: [ + ":com.android.apex.apkrollback.test_v2", + ], } java_test_host { diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java index 02597d548361..12f1750fb78c 100644 --- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java @@ -49,6 +49,11 @@ import java.util.function.Consumer; public class StagedInstallInternalTest { private static final String TAG = StagedInstallInternalTest.class.getSimpleName(); + private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test"; + private static final TestApp TEST_APEX_WITH_APK_V1 = new TestApp("TestApexWithApkV1", + APK_IN_APEX_TESTAPEX_NAME, 1, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v1.apex"); + private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2", + APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex"); private File mTestStateFile = new File( InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(), @@ -82,6 +87,24 @@ public class StagedInstallInternalTest { } @Test + public void testDuplicateApkInApexShouldFail_Commit() throws Exception { + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + // Duplicate packages(TestApp.A) in TEST_APEX_WITH_APK_V2(apk-in-apex) and TestApp.A2(apk) + // should fail to install. + int sessionId = Install.multi(TEST_APEX_WITH_APK_V2, TestApp.A2).setStaged().commit(); + storeSessionId(sessionId); + } + + @Test + public void testDuplicateApkInApexShouldFail_Verify() throws Exception { + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + int sessionId = retrieveLastSessionId(); + PackageInstaller.SessionInfo info = + InstallUtils.getPackageInstaller().getSessionInfo(sessionId); + assertThat(info.isStagedSessionFailed()).isTrue(); + } + + @Test public void testSystemServerRestartDoesNotAffectStagedSessions_Commit() throws Exception { int sessionId = Install.single(TestApp.A1).setStaged().commit(); assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1); diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index 5285b04f67d7..792e29d93be2 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -22,12 +22,16 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; -import com.android.cts.install.lib.host.InstallUtilsHost; +import android.cts.install.lib.host.InstallUtilsHost; + +import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; import com.android.ddmlib.Log; import com.android.tests.rollback.host.AbandonSessionsRule; import com.android.tests.util.ModuleTestUtils; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.tradefed.util.CommandResult; +import com.android.tradefed.util.CommandStatus; import com.android.tradefed.util.ProcessInfo; import org.junit.After; @@ -48,6 +52,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this); private static final String SHIM_V2 = "com.android.apex.cts.shim.v2.apex"; private static final String APK_A = "TestAppAv1.apk"; + private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test"; private final ModuleTestUtils mTestUtils = new ModuleTestUtils(this); private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this); @@ -73,6 +78,8 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { } catch (AssertionError e) { Log.e(TAG, e); } + deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex", + "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex"); } @Before @@ -85,6 +92,55 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { cleanUp(); } + /** + * Deletes files and reboots the device if necessary. + * @param files the paths of files which might contain wildcards + */ + private void deleteFiles(String... files) throws Exception { + boolean found = false; + for (String file : files) { + CommandResult result = getDevice().executeShellV2Command("ls " + file); + if (result.getStatus() == CommandStatus.SUCCESS) { + found = true; + break; + } + } + + if (found) { + if (!getDevice().isAdbRoot()) { + getDevice().enableAdbRoot(); + } + getDevice().remountSystemWritable(); + for (String file : files) { + getDevice().executeShellCommand("rm -rf " + file); + } + getDevice().reboot(); + } + } + + private void pushTestApex() throws Exception { + CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild()); + final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex"; + final File apex = buildHelper.getTestFile(fileName); + if (!getDevice().isAdbRoot()) { + getDevice().enableAdbRoot(); + } + getDevice().remountSystemWritable(); + assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName)); + getDevice().reboot(); + } + + /** + * Tests that duplicate packages in apk-in-apex and apk should fail to install. + */ + @Test + public void testDuplicateApkInApexShouldFail() throws Exception { + pushTestApex(); + runPhase("testDuplicateApkInApexShouldFail_Commit"); + getDevice().reboot(); + runPhase("testDuplicateApkInApexShouldFail_Verify"); + } + @Test public void testSystemServerRestartDoesNotAffectStagedSessions() throws Exception { runPhase("testSystemServerRestartDoesNotAffectStagedSessions_Commit"); diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index a384687e06f6..ab12ac0ef56e 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -28,11 +28,17 @@ import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; +import static android.net.INetd.PERMISSION_INTERNET; +import static android.net.INetd.PERMISSION_NONE; +import static android.net.INetd.PERMISSION_SYSTEM; +import static android.net.INetd.PERMISSION_UNINSTALLED; +import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.os.Process.SYSTEM_UID; import static com.android.server.connectivity.PermissionMonitor.NETWORK; import static com.android.server.connectivity.PermissionMonitor.SYSTEM; +import static com.android.server.connectivity.PermissionMonitor.UidNetdPermissionInfo; import static junit.framework.Assert.fail; @@ -63,7 +69,7 @@ import android.net.UidRange; import android.os.Build; import android.os.UserHandle; import android.os.UserManager; -import android.util.SparseIntArray; +import android.util.SparseArray; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -312,7 +318,7 @@ public class PermissionMonitorTest { // Add hook to verify and track result of setPermission. doAnswer((InvocationOnMock invocation) -> { final Object[] args = invocation.getArguments(); - final Boolean isSystem = args[0].equals(INetd.PERMISSION_SYSTEM); + final Boolean isSystem = args[0].equals(PERMISSION_SYSTEM); for (final int uid : (int[]) args[1]) { // TODO: Currently, permission monitor will send duplicate commands for each uid // corresponding to each user. Need to fix that and uncomment below test. @@ -555,39 +561,40 @@ public class PermissionMonitorTest { // SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission. // SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission. - SparseIntArray netdPermissionsAppIds = new SparseIntArray(); - netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET); - netdPermissionsAppIds.put(MOCK_UID2, INetd.PERMISSION_NONE); - netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS); - netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS); + final SparseArray<UidNetdPermissionInfo> uidsPermInfo = new SparseArray<>(); + uidsPermInfo.put(MOCK_UID1, new UidNetdPermissionInfo(PERMISSION_INTERNET)); + uidsPermInfo.put(MOCK_UID2, new UidNetdPermissionInfo(PERMISSION_NONE)); + uidsPermInfo.put(SYSTEM_UID1, new UidNetdPermissionInfo( + PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS)); + uidsPermInfo.put(SYSTEM_UID2, new UidNetdPermissionInfo(PERMISSION_UPDATE_DEVICE_STATS)); // Send the permission information to netd, expect permission updated. - mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds); + mPermissionMonitor.sendPackagePermissionsToNetd(uidsPermInfo); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID2}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS, + mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{MOCK_UID2}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID2}); // Update permission of MOCK_UID1, expect new permission show up. - mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1, - INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1, new UidNetdPermissionInfo( + PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS)); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); // Change permissions of SYSTEM_UID2, expect new permission show up and old permission // revoked. - mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2, - INetd.PERMISSION_INTERNET); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2}); + mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2, new UidNetdPermissionInfo( + PERMISSION_INTERNET)); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{SYSTEM_UID2}); // Revoke permission from SYSTEM_UID1, expect no permission stored. - mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.PERMISSION_NONE); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1}); + mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, new UidNetdPermissionInfo( + PERMISSION_NONE)); + mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{SYSTEM_UID1}); } private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions) @@ -611,11 +618,11 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID2}); } @Test @@ -623,8 +630,8 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); // Install another package with the same uid and no permissions should not cause the UID to // lose permissions. @@ -633,8 +640,8 @@ public class PermissionMonitorTest { when(mPackageManager.getPackagesForUid(MOCK_UID1)) .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2}); mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); } @Test @@ -642,12 +649,12 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{}); mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); } @Test @@ -655,16 +662,16 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{}); removeAllPermissions(MOCK_UID1); mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1}); } @Test @@ -672,10 +679,10 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{MOCK_UID1}); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1}); } @Test @@ -683,8 +690,8 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); // Mock another package with the same uid but different permissions. final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1); @@ -695,7 +702,7 @@ public class PermissionMonitorTest { addPermissions(MOCK_UID1, INTERNET); mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1}); } @Test diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index de1c5759ee87..e8c4ee9c628d 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -270,12 +270,12 @@ public class VpnTest { } @Test - public void testUidWhiteAndBlacklist() throws Exception { + public void testUidAllowAndDenylist() throws Exception { final Vpn vpn = createVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); final String[] packages = {PKGS[0], PKGS[1], PKGS[2]}; - // Whitelist + // Allowed list final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, Arrays.asList(packages), null); assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { @@ -283,7 +283,7 @@ public class VpnTest { new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]) })), allow); - // Blacklist + // Denied list final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, Arrays.asList(packages)); assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { @@ -354,11 +354,11 @@ public class VpnTest { } @Test - public void testLockdownWhitelist() throws Exception { + public void testLockdownAllowlist() throws Exception { final Vpn vpn = createVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); - // Set always-on with lockdown and whitelist app PKGS[2] from lockdown. + // Set always-on with lockdown and allow app PKGS[2] from lockdown. assertTrue(vpn.setAlwaysOnPackage( PKGS[1], true, Collections.singletonList(PKGS[2]), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { @@ -368,7 +368,7 @@ public class VpnTest { assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); - // Change whitelisted app to PKGS[3]. + // Change allowed app list to PKGS[3]. assertTrue(vpn.setAlwaysOnPackage( PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { @@ -395,7 +395,7 @@ public class VpnTest { assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); - // Remove the whitelist. + // Remove the list of allowed packages. assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1), @@ -408,7 +408,7 @@ public class VpnTest { user.start + PKG_UIDS[3]); assertUnblocked(vpn, user.start + PKG_UIDS[0]); - // Add the whitelist. + // Add the list of allowed packages. assertTrue(vpn.setAlwaysOnPackage( PKGS[0], true, Collections.singletonList(PKGS[1]), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { @@ -421,12 +421,12 @@ public class VpnTest { assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]); - // Try whitelisting a package with a comma, should be rejected. + // Try allowing a package with a comma, should be rejected. assertFalse(vpn.setAlwaysOnPackage( PKGS[0], true, Collections.singletonList("a.b,c.d"), mKeyStore)); - // Pass a non-existent packages in the whitelist, they (and only they) should be ignored. - // Whitelisted package should change from PGKS[1] to PKGS[2]. + // Pass a non-existent packages in the allowlist, they (and only they) should be ignored. + // allowed package should change from PGKS[1] to PKGS[2]. assertTrue(vpn.setAlwaysOnPackage( PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{ diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp index ce551bd0cc10..0be80d31990a 100644 --- a/tools/protologtool/Android.bp +++ b/tools/protologtool/Android.bp @@ -2,9 +2,9 @@ java_library_host { name: "protologtool-lib", srcs: [ "src/com/android/protolog/tool/**/*.kt", + ":protolog-common-src", ], static_libs: [ - "protolog-common", "javaparser", "platformprotos", "jsonlib", diff --git a/tools/protologtool/src/com/android/protolog/tool/LogParser.kt b/tools/protologtool/src/com/android/protolog/tool/LogParser.kt index a59038fc99a0..645c5672da64 100644 --- a/tools/protologtool/src/com/android/protolog/tool/LogParser.kt +++ b/tools/protologtool/src/com/android/protolog/tool/LogParser.kt @@ -16,16 +16,15 @@ package com.android.protolog.tool +import com.android.internal.protolog.ProtoLogFileProto +import com.android.internal.protolog.ProtoLogMessage +import com.android.internal.protolog.common.InvalidFormatStringException +import com.android.internal.protolog.common.LogDataType import com.android.json.stream.JsonReader -import com.android.server.protolog.common.InvalidFormatStringException -import com.android.server.protolog.common.LogDataType -import com.android.server.protolog.ProtoLogMessage -import com.android.server.protolog.ProtoLogFileProto import java.io.BufferedReader import java.io.InputStream import java.io.InputStreamReader import java.io.PrintStream -import java.lang.Exception import java.text.SimpleDateFormat import java.util.Date import java.util.Locale diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogGroupReader.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogGroupReader.kt index 75493b6427cb..42b628b0e262 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogGroupReader.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogGroupReader.kt @@ -17,7 +17,7 @@ package com.android.protolog.tool import com.android.protolog.tool.Constants.ENUM_VALUES_METHOD -import com.android.server.protolog.common.IProtoLogGroup +import com.android.internal.protolog.common.IProtoLogGroup import java.io.File import java.net.URLClassLoader diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt index 36ea41129450..27e61a139451 100644 --- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt +++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt @@ -16,7 +16,7 @@ package com.android.protolog.tool -import com.android.server.protolog.common.LogDataType +import com.android.internal.protolog.common.LogDataType import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.NodeList @@ -89,7 +89,7 @@ class SourceTransformer( // Out: ProtoLog.e(GROUP, 1234, 0, null, arg) newCall.arguments.add(2, IntegerLiteralExpr(typeMask)) // Replace call to a stub method with an actual implementation. - // Out: com.android.server.protolog.ProtoLogImpl.e(GROUP, 1234, null, arg) + // Out: ProtoLogImpl.e(GROUP, 1234, null, arg) newCall.setScope(protoLogImplClassNode) // Create a call to ProtoLog$Cache.GROUP_enabled // Out: com.android.server.protolog.ProtoLog$Cache.GROUP_enabled @@ -119,9 +119,9 @@ class SourceTransformer( } blockStmt.addStatement(ExpressionStmt(newCall)) // Create an IF-statement with the previously created condition. - // Out: if (com.android.server.protolog.ProtoLogImpl.isEnabled(GROUP)) { + // Out: if (ProtoLogImpl.isEnabled(GROUP)) { // long protoLogParam0 = arg; - // com.android.server.protolog.ProtoLogImpl.e(GROUP, 1234, 0, null, protoLogParam0); + // ProtoLogImpl.e(GROUP, 1234, 0, null, protoLogParam0); // } ifStmt = IfStmt(isLogEnabled, blockStmt, null) } else { diff --git a/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt index cf36651c3e39..3cfbb435a764 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt @@ -31,7 +31,7 @@ class CommandOptionsTest { private const val TEST_PROTOLOG_CLASS = "com.android.server.wm.ProtoLog" private const val TEST_PROTOLOGIMPL_CLASS = "com.android.server.wm.ProtoLogImpl" private const val TEST_PROTOLOGCACHE_CLASS = "com.android.server.wm.ProtoLog\$Cache" - private const val TEST_PROTOLOGGROUP_CLASS = "com.android.server.wm.ProtoLogGroup" + private const val TEST_PROTOLOGGROUP_CLASS = "com.android.internal.protolog.ProtoLogGroup" private const val TEST_PROTOLOGGROUP_JAR = "out/soong/.intermediates/frameworks/base/" + "services/core/services.core.wm.protologgroups/android_common/javac/" + "services.core.wm.protologgroups.jar" diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt index dd8a0b1c50b4..0d2b91d6cfb8 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt @@ -33,8 +33,8 @@ class EndToEndTest { val output = run( src = "frameworks/base/org/example/Example.java" to """ package org.example; - import com.android.server.protolog.common.ProtoLog; - import static com.android.server.wm.ProtoLogGroup.GROUP; + import com.android.internal.protolog.common.ProtoLog; + import static com.android.internal.protolog.ProtoLogGroup.GROUP; class Example { void method() { @@ -46,11 +46,11 @@ class EndToEndTest { """.trimIndent(), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("transform-protolog-calls", - "--protolog-class", "com.android.server.protolog.common.ProtoLog", - "--protolog-impl-class", "com.android.server.protolog.ProtoLogImpl", + "--protolog-class", "com.android.internal.protolog.common.ProtoLog", + "--protolog-impl-class", "com.android.internal.protolog.ProtoLogImpl", "--protolog-cache-class", - "com.android.server.protolog.ProtoLog${"\$\$"}Cache", - "--loggroups-class", "com.android.server.wm.ProtoLogGroup", + "com.android.server.wm.ProtoLogCache", + "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--output-srcjar", "out.srcjar", "frameworks/base/org/example/Example.java")) @@ -64,8 +64,8 @@ class EndToEndTest { val output = run( src = "frameworks/base/org/example/Example.java" to """ package org.example; - import com.android.server.protolog.common.ProtoLog; - import static com.android.server.wm.ProtoLogGroup.GROUP; + import com.android.internal.protolog.common.ProtoLog; + import static com.android.internal.protolog.ProtoLogGroup.GROUP; class Example { void method() { @@ -77,8 +77,8 @@ class EndToEndTest { """.trimIndent(), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("generate-viewer-config", - "--protolog-class", "com.android.server.protolog.common.ProtoLog", - "--loggroups-class", "com.android.server.wm.ProtoLogGroup", + "--protolog-class", "com.android.internal.protolog.common.ProtoLog", + "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--viewer-conf", "out.json", "frameworks/base/org/example/Example.java")) diff --git a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt index 04a3bfa499d8..67a31da87081 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt @@ -17,8 +17,8 @@ package com.android.protolog.tool import com.android.json.stream.JsonReader -import com.android.server.protolog.ProtoLogMessage -import com.android.server.protolog.ProtoLogFileProto +import com.android.internal.protolog.ProtoLogMessage +import com.android.internal.protolog.ProtoLogFileProto import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt index 53c69c47d052..eff64a31367a 100644 --- a/wifi/api/system-current.txt +++ b/wifi/api/system-current.txt @@ -326,6 +326,8 @@ package android.net.wifi { field @Deprecated public static final int METERED_OVERRIDE_METERED = 1; // 0x1 field @Deprecated public static final int METERED_OVERRIDE_NONE = 0; // 0x0 field @Deprecated public static final int METERED_OVERRIDE_NOT_METERED = 2; // 0x2 + field @Deprecated public static final int RANDOMIZATION_AUTO = 3; // 0x3 + field @Deprecated public static final int RANDOMIZATION_ENHANCED = 2; // 0x2 field @Deprecated public static final int RANDOMIZATION_NONE = 0; // 0x0 field @Deprecated public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1 field @Deprecated public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11 diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 71f0ab8087ab..1588bf72c969 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -1130,7 +1130,9 @@ public class WifiConfiguration implements Parcelable { @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"RANDOMIZATION_"}, value = { RANDOMIZATION_NONE, - RANDOMIZATION_PERSISTENT}) + RANDOMIZATION_PERSISTENT, + RANDOMIZATION_ENHANCED, + RANDOMIZATION_AUTO}) public @interface MacRandomizationSetting {} /** @@ -1147,14 +1149,30 @@ public class WifiConfiguration implements Parcelable { public static final int RANDOMIZATION_PERSISTENT = 1; /** + * Use a randomly generated MAC address for connections to this network. + * This option does not persist the randomized MAC address. + * @hide + */ + @SystemApi + public static final int RANDOMIZATION_ENHANCED = 2; + + /** + * Let the wifi framework automatically decide the MAC randomization strategy. + * @hide + */ + @SystemApi + public static final int RANDOMIZATION_AUTO = 3; + + /** * Level of MAC randomization for this network. - * One of {@link #RANDOMIZATION_NONE} or {@link #RANDOMIZATION_PERSISTENT}. - * By default this field is set to {@link #RANDOMIZATION_PERSISTENT}. + * One of {@link #RANDOMIZATION_NONE}, {@link #RANDOMIZATION_AUTO}, + * {@link #RANDOMIZATION_PERSISTENT} or {@link #RANDOMIZATION_ENHANCED}. + * By default this field is set to {@link #RANDOMIZATION_AUTO}. * @hide */ @SystemApi @MacRandomizationSetting - public int macRandomizationSetting = RANDOMIZATION_PERSISTENT; + public int macRandomizationSetting = RANDOMIZATION_AUTO; /** * @hide diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java index fa806e7797cd..282757ac5a14 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java @@ -448,6 +448,16 @@ public final class Credential implements Parcelable { return new UserCredential[size]; } }; + + /** + * Get a unique identifier for UserCredential. + * + * @hide + * @return a Unique identifier for a UserCredential object + */ + public int getUniqueId() { + return Objects.hash(mUsername); + } } private UserCredential mUserCredential = null; /** @@ -1037,7 +1047,8 @@ public final class Credential implements Parcelable { * @return a Unique identifier for a Credential object */ public int getUniqueId() { - return Objects.hash(mUserCredential, mCertCredential, mSimCredential, mRealm); + return Objects.hash(mUserCredential != null ? mUserCredential.getUniqueId() : 0, + mCertCredential, mSimCredential, mRealm); } @Override diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java index 224c4bed9d5b..8f34579f6a5d 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java @@ -313,9 +313,7 @@ public final class HomeSp implements Parcelable { * @return a Unique identifier for a HomeSp object */ public int getUniqueId() { - return Objects.hash(mFqdn, mFriendlyName, mHomeNetworkIds, Arrays.hashCode(mMatchAllOis), - Arrays.hashCode(mMatchAnyOis), Arrays.hashCode(mOtherHomePartners), - Arrays.hashCode(mRoamingConsortiumOis)); + return Objects.hash(mFqdn); } diff --git a/wifi/tests/src/android/net/wifi/FakeKeys.java b/wifi/tests/src/android/net/wifi/FakeKeys.java index c0d60c33f99c..641b891a1f4d 100644 --- a/wifi/tests/src/android/net/wifi/FakeKeys.java +++ b/wifi/tests/src/android/net/wifi/FakeKeys.java @@ -214,6 +214,35 @@ public class FakeKeys { }; public static final PrivateKey RSA_KEY1 = loadPrivateRSAKey(FAKE_RSA_KEY_1); + private static final String CLIENT_SUITE_B_RSA3072_CERT_STRING = + "-----BEGIN CERTIFICATE-----\n" + + "MIIERzCCAq8CFDopjyNgaj+c2TN2k06h7okEWpHJMA0GCSqGSIb3DQEBDAUAMF4x\n" + + "CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDTVRWMRAwDgYDVQQK\n" + + "DAdBbmRyb2lkMQ4wDAYDVQQLDAVXaS1GaTESMBAGA1UEAwwJdW5pdGVzdENBMB4X\n" + + "DTIwMDcyMTAyMjkxMVoXDTMwMDUzMDAyMjkxMVowYjELMAkGA1UEBhMCVVMxCzAJ\n" + + "BgNVBAgMAkNBMQwwCgYDVQQHDANNVFYxEDAOBgNVBAoMB0FuZHJvaWQxDjAMBgNV\n" + + "BAsMBVdpLUZpMRYwFAYDVQQDDA11bml0ZXN0Q2xpZW50MIIBojANBgkqhkiG9w0B\n" + + "AQEFAAOCAY8AMIIBigKCAYEAwSK3C5K5udtCKTnE14e8z2cZvwmB4Xe+a8+7QLud\n" + + "Hooc/lQzClgK4MbVUC0D3FE+U32C78SxKoTaRWtvPmNm+UaFT8KkwyUno/dv+2XD\n" + + "pd/zARQ+3FwAfWopAhEyCVSxwsCa+slQ4juRIMIuUC1Mm0NaptZyM3Tj/ICQEfpk\n" + + "o9qVIbiK6eoJMTkY8EWfAn7RTFdfR1OLuO0mVOjgLW9/+upYv6hZ19nAMAxw4QTJ\n" + + "x7lLwALX7B+tDYNEZHDqYL2zyvQWAj2HClere8QYILxkvktgBg2crEJJe4XbDH7L\n" + + "A3rrXmsiqf1ZbfFFEzK9NFqovL+qGh+zIP+588ShJFO9H/RDnDpiTnAFTWXQdTwg\n" + + "szSS0Vw2PB+JqEABAa9DeMvXT1Oy+NY3ItPHyy63nQZVI2rXANw4NhwS0Z6DF+Qs\n" + + "TNrj+GU7e4SG/EGR8SvldjYfQTWFLg1l/UT1hOOkQZwdsaW1zgKyeuiFB2KdMmbA\n" + + "Sq+Ux1L1KICo0IglwWcB/8nnAgMBAAEwDQYJKoZIhvcNAQEMBQADggGBAMYwJkNw\n" + + "BaCviKFmReDTMwWPRy4AMNViEeqAXgERwDEKwM7efjsaj5gctWfKsxX6UdLzkhgg\n" + + "6S/T6PxVWKzJ6l7SoOuTa6tMQOZp+h3R1mdfEQbw8B5cXBxZ+batzAai6Fiy1FKS\n" + + "/ka3INbcGfYuIYghfTrb4/NJKN06ZaQ1bpPwq0e4gN7800T2nbawvSf7r+8ZLcG3\n" + + "6bGCjRMwDSIipNvOwoj3TG315XC7TccX5difQ4sKOY+d2MkVJ3RiO0Ciw2ZbEW8d\n" + + "1FH5vUQJWnBUfSFznosGzLwH3iWfqlP+27jNE+qB2igEwCRFgVAouURx5ou43xuX\n" + + "qf6JkdI3HTJGLIWxkp7gOeln4dEaYzKjYw+P0VqJvKVqQ0IXiLjHgE0J9p0vgyD6\n" + + "HVVcP7U8RgqrbIjL1QgHU4KBhGi+WSUh/mRplUCNvHgcYdcHi/gHpj/j6ubwqIGV\n" + + "z4iSolAHYTmBWcLyE0NgpzE6ntp+53r2KaUJA99l2iGVzbWTwqPSm0XAVw==\n" + + "-----END CERTIFICATE-----\n"; + public static final X509Certificate CLIENT_SUITE_B_RSA3072_CERT = + loadCertificate(CLIENT_SUITE_B_RSA3072_CERT_STRING); + private static X509Certificate loadCertificate(String blob) { try { final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java index 638efb9f14ee..8270d643ca65 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java @@ -23,6 +23,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import android.net.wifi.EAPConstants; +import android.net.wifi.FakeKeys; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; import android.os.Parcel; @@ -32,6 +34,11 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -383,19 +390,39 @@ public class PasspointConfigurationTest { } /** - * Verify that the unique identifier generated is different for two instances with different - * HomeSp node + * Verify that the unique identifier generated is the same for two instances with different + * HomeSp node but same FQDN * * @throws Exception */ @Test - public void validateUniqueIdDifferentHomeSp() throws Exception { + public void validateUniqueIdDifferentHomeSpSameFqdn() throws Exception { PasspointConfiguration config1 = PasspointTestUtils.createConfig(); - // Modify config2's RCOIs to a different set of values + // Modify config2's RCOIs and friendly name to a different set of values PasspointConfiguration config2 = PasspointTestUtils.createConfig(); HomeSp homeSp = config2.getHomeSp(); homeSp.setRoamingConsortiumOis(new long[] {0xaa, 0xbb}); + homeSp.setFriendlyName("Some other name"); + config2.setHomeSp(homeSp); + + assertEquals(config1.getUniqueId(), config2.getUniqueId()); + } + + /** + * Verify that the unique identifier generated is different for two instances with the same + * HomeSp node but different FQDN + * + * @throws Exception + */ + @Test + public void validateUniqueIdSameHomeSpDifferentFqdn() throws Exception { + PasspointConfiguration config1 = PasspointTestUtils.createConfig(); + + // Modify config2's FQDN to a different value + PasspointConfiguration config2 = PasspointTestUtils.createConfig(); + HomeSp homeSp = config2.getHomeSp(); + homeSp.setFqdn("fqdn2.com"); config2.setHomeSp(homeSp); assertNotEquals(config1.getUniqueId(), config2.getUniqueId()); @@ -403,15 +430,15 @@ public class PasspointConfigurationTest { /** * Verify that the unique identifier generated is different for two instances with different - * Credential node + * SIM Credential node * * @throws Exception */ @Test - public void validateUniqueIdDifferentCredential() throws Exception { + public void validateUniqueIdDifferentSimCredential() throws Exception { PasspointConfiguration config1 = PasspointTestUtils.createConfig(); - // Modify config2's RCOIs to a different set of values + // Modify config2's realm and SIM credential to a different set of values PasspointConfiguration config2 = PasspointTestUtils.createConfig(); Credential credential = config2.getCredential(); credential.setRealm("realm2.example.com"); @@ -422,6 +449,157 @@ public class PasspointConfigurationTest { } /** + * Verify that the unique identifier generated is different for two instances with different + * Realm in the Credential node + * + * @throws Exception + */ + @Test + public void validateUniqueIdDifferentRealm() throws Exception { + PasspointConfiguration config1 = PasspointTestUtils.createConfig(); + + // Modify config2's realm to a different set of values + PasspointConfiguration config2 = PasspointTestUtils.createConfig(); + Credential credential = config2.getCredential(); + credential.setRealm("realm2.example.com"); + config2.setCredential(credential); + + assertNotEquals(config1.getUniqueId(), config2.getUniqueId()); + } + + /** + * Verify that the unique identifier generated is the same for two instances with different + * password and same username in the User Credential node + * + * @throws Exception + */ + @Test + public void validateUniqueIdSameUserInUserCredential() throws Exception { + PasspointConfiguration config1 = PasspointTestUtils.createConfig(); + Credential credential = createCredentialWithUserCredential("user", "passwd"); + config1.setCredential(credential); + + // Modify config2's Passpowrd to a different set of values + PasspointConfiguration config2 = PasspointTestUtils.createConfig(); + credential = createCredentialWithUserCredential("user", "newpasswd"); + config2.setCredential(credential); + + assertEquals(config1.getUniqueId(), config2.getUniqueId()); + } + + /** + * Verify that the unique identifier generated is different for two instances with different + * username in the User Credential node + * + * @throws Exception + */ + @Test + public void validateUniqueIdDifferentUserCredential() throws Exception { + PasspointConfiguration config1 = PasspointTestUtils.createConfig(); + Credential credential = createCredentialWithUserCredential("user", "passwd"); + config1.setCredential(credential); + + // Modify config2's username to a different value + PasspointConfiguration config2 = PasspointTestUtils.createConfig(); + credential = createCredentialWithUserCredential("user2", "passwd"); + config2.setCredential(credential); + + assertNotEquals(config1.getUniqueId(), config2.getUniqueId()); + } + + /** + * Verify that the unique identifier generated is different for two instances with different + * Cert Credential node + * + * @throws Exception + */ + @Test + public void validateUniqueIdDifferentCertCredential() throws Exception { + PasspointConfiguration config1 = PasspointTestUtils.createConfig(); + Credential credential = createCredentialWithCertificateCredential(true, true); + config1.setCredential(credential); + + // Modify config2's cert credential to a different set of values + PasspointConfiguration config2 = PasspointTestUtils.createConfig(); + credential = createCredentialWithCertificateCredential(false, false); + config2.setCredential(credential); + + assertNotEquals(config1.getUniqueId(), config2.getUniqueId()); + } + + /** + * Helper function for generating certificate credential for testing. + * + * @return {@link Credential} + */ + private static Credential createCredentialWithCertificateCredential(Boolean useCaCert0, + Boolean useCert0) + throws NoSuchAlgorithmException, CertificateEncodingException { + Credential.CertificateCredential certCred = new Credential.CertificateCredential(); + certCred.setCertType("x509v3"); + if (useCert0) { + certCred.setCertSha256Fingerprint( + MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded())); + } else { + certCred.setCertSha256Fingerprint(MessageDigest.getInstance("SHA-256") + .digest(FakeKeys.CLIENT_SUITE_B_RSA3072_CERT.getEncoded())); + } + return createCredential(null, certCred, null, new X509Certificate[] {FakeKeys.CLIENT_CERT}, + FakeKeys.RSA_KEY1, useCaCert0 ? FakeKeys.CA_CERT0 : FakeKeys.CA_CERT1); + } + + /** + * Helper function for generating user credential for testing. + * + * @return {@link Credential} + */ + private static Credential createCredentialWithUserCredential(String username, String password) { + Credential.UserCredential userCred = new Credential.UserCredential(); + userCred.setUsername(username); + userCred.setPassword(password); + userCred.setMachineManaged(true); + userCred.setAbleToShare(true); + userCred.setSoftTokenApp("TestApp"); + userCred.setEapType(EAPConstants.EAP_TTLS); + userCred.setNonEapInnerMethod("MS-CHAP"); + return createCredential(userCred, null, null, null, null, FakeKeys.CA_CERT0); + } + + /** + * Helper function for generating Credential for testing. + * + * @param userCred Instance of UserCredential + * @param certCred Instance of CertificateCredential + * @param simCred Instance of SimCredential + * @param clientCertificateChain Chain of client certificates + * @param clientPrivateKey Client private key + * @param caCerts CA certificates + * @return {@link Credential} + */ + private static Credential createCredential(Credential.UserCredential userCred, + Credential.CertificateCredential certCred, + Credential.SimCredential simCred, + X509Certificate[] clientCertificateChain, PrivateKey clientPrivateKey, + X509Certificate... caCerts) { + Credential cred = new Credential(); + cred.setCreationTimeInMillis(123455L); + cred.setExpirationTimeInMillis(2310093L); + cred.setRealm("realm"); + cred.setCheckAaaServerCertStatus(true); + cred.setUserCredential(userCred); + cred.setCertCredential(certCred); + cred.setSimCredential(simCred); + if (caCerts != null && caCerts.length == 1) { + cred.setCaCertificate(caCerts[0]); + } else { + cred.setCaCertificates(caCerts); + } + cred.setClientCertificateChain(clientCertificateChain); + cred.setClientPrivateKey(clientPrivateKey); + return cred; + } + + /** * Verify that the unique identifier API generates an exception if HomeSP is not initialized. * * @throws Exception diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java index 829d8f0a9a3a..a44df40a8e97 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java @@ -593,10 +593,10 @@ public class CredentialTest { } /** - * Verify that unique identifiers are different for a credential with different values + * Verify that unique identifiers are different for a credential with different username */ @Test - public void testUniqueIdDifferentForUserCredentialsWithDifferentValues() throws Exception { + public void testUniqueIdDifferentForUserCredentialsWithDifferentUsername() throws Exception { Credential userCred1 = createCredentialWithUserCredential(); Credential userCred2 = createCredentialWithUserCredential(); userCred2.getUserCredential().setUsername("anotheruser"); @@ -605,7 +605,24 @@ public class CredentialTest { } /** - * Verify that unique identifiers are different for a credential with different values + * Verify that unique identifiers are different for a credential with different password and + * other values other than username + */ + @Test + public void testUniqueIdSameForUserCredentialsWithDifferentPassword() throws Exception { + Credential userCred1 = createCredentialWithUserCredential(); + Credential userCred2 = createCredentialWithUserCredential(); + userCred2.getUserCredential().setPassword("someotherpassword!"); + userCred2.getUserCredential().setMachineManaged(false); + userCred2.getUserCredential().setAbleToShare(false); + userCred2.getUserCredential().setSoftTokenApp("TestApp2"); + userCred2.getUserCredential().setNonEapInnerMethod("PAP"); + + assertEquals(userCred1.getUniqueId(), userCred2.getUniqueId()); + } + + /** + * Verify that unique identifiers are different for a cert credential with different values */ @Test public void testUniqueIdDifferentForCertCredentialsWithDifferentValues() throws Exception { |