Merge "Call onOutgoingEmergencyCall only once."
diff --git a/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
index 050fecd..d3938f4 100644
--- a/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
@@ -17,7 +17,6 @@
import android.content.Context;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.view.Display;
@@ -136,4 +135,22 @@
}
}
}
+
+ @Test
+ public void getDisplayMetrics() {
+ ResourcesManager resourcesManager = ResourcesManager.getInstance();
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Invalidate cache.
+ resourcesManager.applyConfigurationToResourcesLocked(
+ resourcesManager.getConfiguration(), null);
+ state.resumeTiming();
+
+ // Invoke twice for testing cache.
+ resourcesManager.getDisplayMetrics();
+ resourcesManager.getDisplayMetrics();
+ }
+ }
}
diff --git a/api/current.txt b/api/current.txt
index c6af6be..e5baa7c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11617,6 +11617,16 @@
field public int version;
}
+ public final class FileChecksum implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getKind();
+ method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException;
+ method @Nullable public String getSplitName();
+ method @NonNull public byte[] getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.FileChecksum> CREATOR;
+ }
+
public final class InstallSourceInfo implements android.os.Parcelable {
method public int describeContents();
method @Nullable public String getInitiatingPackageName();
@@ -11992,6 +12002,7 @@
method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public CharSequence getBackgroundPermissionOptionLabel();
method @Nullable public abstract android.content.pm.ChangedPackages getChangedPackages(@IntRange(from=0) int);
+ method public void getChecksums(@NonNull String, boolean, int, @Nullable java.util.List<java.security.cert.Certificate>, @NonNull android.content.IntentSender) throws java.security.cert.CertificateEncodingException, java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName);
method @NonNull public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
method @Nullable public abstract android.graphics.drawable.Drawable getDrawable(@NonNull String, @DrawableRes int, @Nullable android.content.pm.ApplicationInfo);
@@ -12082,6 +12093,7 @@
field public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; // 0x3
field public static final int COMPONENT_ENABLED_STATE_ENABLED = 1; // 0x1
field public static final int DONT_KILL_APP = 1; // 0x1
+ field public static final String EXTRA_CHECKSUMS = "android.content.pm.extra.CHECKSUMS";
field public static final String EXTRA_VERIFICATION_ID = "android.content.pm.extra.VERIFICATION_ID";
field public static final String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT";
field public static final String FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS = "android.software.activities_on_secondary_displays";
@@ -12236,6 +12248,8 @@
field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff
@@ -12245,9 +12259,16 @@
field public static final int SIGNATURE_SECOND_NOT_SIGNED = -2; // 0xfffffffe
field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc
field public static final int SYNCHRONOUS = 2; // 0x2
+ field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
+ field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
+ field public static final int WHOLE_MD5 = 2; // 0x2
+ field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1
+ field public static final int WHOLE_SHA1 = 4; // 0x4
+ field public static final int WHOLE_SHA256 = 8; // 0x8
+ field public static final int WHOLE_SHA512 = 16; // 0x10
}
public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
diff --git a/api/system-current.txt b/api/system-current.txt
index 41e8593..00a59bf 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -219,6 +219,7 @@
field public static final String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT";
field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
field public static final String SHUTDOWN = "android.permission.SHUTDOWN";
+ field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE";
field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
diff --git a/api/test-current.txt b/api/test-current.txt
index 529dcf7..5741fe7 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5579,7 +5579,7 @@
method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer();
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer();
}
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 3b65f82..4574b2e 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -25,8 +25,9 @@
using std::unordered_map;
using std::vector;
-CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index)
- : ConditionTracker(id, index) {
+CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index,
+ const uint64_t protoHash)
+ : ConditionTracker(id, index, protoHash) {
VLOG("creating CombinationConditionTracker %lld", (long long)mConditionId);
}
@@ -122,6 +123,49 @@
return true;
}
+bool CombinationConditionTracker::onConfigUpdated(
+ const vector<Predicate>& allConditionProtos, const int index,
+ const vector<sp<ConditionTracker>>& allConditionTrackers,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const unordered_map<int64_t, int>& conditionTrackerMap) {
+ ConditionTracker::onConfigUpdated(allConditionProtos, index, allConditionTrackers,
+ atomMatchingTrackerMap, conditionTrackerMap);
+ mTrackerIndex.clear();
+ mChildren.clear();
+ mUnSlicedChildren.clear();
+ mSlicedChildren.clear();
+ Predicate_Combination combinationCondition = allConditionProtos[mIndex].combination();
+
+ for (const int64_t child : combinationCondition.predicate()) {
+ const auto& it = conditionTrackerMap.find(child);
+
+ if (it == conditionTrackerMap.end()) {
+ ALOGW("Predicate %lld not found in the config", (long long)child);
+ return false;
+ }
+
+ int childIndex = it->second;
+ const sp<ConditionTracker>& childTracker = allConditionTrackers[childIndex];
+
+ // Ensures that the child's tracker indices are updated.
+ if (!childTracker->onConfigUpdated(allConditionProtos, childIndex, allConditionTrackers,
+ atomMatchingTrackerMap, conditionTrackerMap)) {
+ ALOGW("Child update failed %lld ", (long long)child);
+ return false;
+ }
+
+ if (allConditionTrackers[childIndex]->isSliced()) {
+ mSlicedChildren.push_back(childIndex);
+ } else {
+ mUnSlicedChildren.push_back(childIndex);
+ }
+ mChildren.push_back(childIndex);
+ mTrackerIndex.insert(childTracker->getAtomMatchingTrackerIndex().begin(),
+ childTracker->getAtomMatchingTrackerIndex().end());
+ }
+ return true;
+}
+
void CombinationConditionTracker::isConditionMet(
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
const bool isPartialLink,
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index a7fac3d..672d61c 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -24,9 +24,9 @@
namespace os {
namespace statsd {
-class CombinationConditionTracker : public virtual ConditionTracker {
+class CombinationConditionTracker : public ConditionTracker {
public:
- CombinationConditionTracker(const int64_t& id, const int index);
+ CombinationConditionTracker(const int64_t& id, const int index, const uint64_t protoHash);
~CombinationConditionTracker();
@@ -35,6 +35,11 @@
const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
std::vector<ConditionState>& conditionCache) override;
+ bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index,
+ const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const std::unordered_map<int64_t, int>& conditionTrackerMap) override;
+
void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
const std::vector<sp<ConditionTracker>>& mAllConditions,
@@ -102,6 +107,7 @@
std::vector<int> mSlicedChildren;
std::vector<int> mUnSlicedChildren;
+ FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions);
};
} // namespace statsd
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 4e12535..3bf4e63 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -31,18 +31,17 @@
class ConditionTracker : public virtual RefBase {
public:
- ConditionTracker(const int64_t& id, const int index)
+ ConditionTracker(const int64_t& id, const int index, const uint64_t protoHash)
: mConditionId(id),
mIndex(index),
mInitialized(false),
mTrackerIndex(),
mUnSlicedPartCondition(ConditionState::kUnknown),
- mSliced(false){};
+ mSliced(false),
+ mProtoHash(protoHash){};
virtual ~ConditionTracker(){};
- inline const int64_t& getId() { return mConditionId; }
-
// Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
// be done in the constructor, but we do it separately because (1) easy to return a bool to
// indicate whether the initialization is successful. (2) makes unit test easier.
@@ -50,7 +49,7 @@
// fill the condition cache with the current condition.
// allConditionConfig: the list of all Predicate config from statsd_config.
// allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
- // need to call init() on children conditions)
+ // need to call init() on child conditions)
// conditionIdIndexMap: the mapping from condition id to its index.
// stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
// conditionCache: tracks initial conditions of all ConditionTrackers. returns the
@@ -60,6 +59,26 @@
const std::unordered_map<int64_t, int>& conditionIdIndexMap,
std::vector<bool>& stack, std::vector<ConditionState>& conditionCache) = 0;
+ // Update appropriate state on config updates. Primarily, all indices need to be updated.
+ // This predicate and all of its children are guaranteed to be preserved across the update.
+ // This function is recursive and will call onConfigUpdated on child conditions. It does not
+ // manage cycle detection since all preserved conditions should not have any cycles.
+ //
+ // allConditionProtos: the new predicates.
+ // index: the new index of this tracker in allConditionProtos and allConditionTrackers.
+ // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
+ // need to call onConfigUpdated() on child conditions)
+ // [atomMatchingTrackerMap]: map of atom matcher id to index after the config update
+ // [conditionTrackerMap]: map of condition tracker id to index after the config update.
+ // returns whether or not the update is successful
+ virtual bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index,
+ const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const std::unordered_map<int64_t, int>& conditionTrackerMap) {
+ mIndex = index;
+ return true;
+ }
+
// evaluate current condition given the new event.
// event: the new log event
// eventMatcherValues: the results of the AtomMatchingTrackers. AtomMatchingTrackers always
@@ -112,6 +131,10 @@
return mConditionId;
}
+ inline uint64_t getProtoHash() const {
+ return mProtoHash;
+ }
+
virtual void getTrueSlicedDimensions(
const std::vector<sp<ConditionTracker>>& allConditions,
std::set<HashableDimensionKey>* dimensions) const = 0;
@@ -133,7 +156,7 @@
const int64_t mConditionId;
// the index of this condition in the manager's condition list.
- const int mIndex;
+ int mIndex;
// if it's properly initialized.
bool mInitialized;
@@ -151,6 +174,12 @@
ConditionState mUnSlicedPartCondition;
bool mSliced;
+
+ // Hash of the Predicate's proto bytes from StatsdConfig.
+ // Used to determine if the definition of this condition has changed across a config update.
+ const uint64_t mProtoHash;
+
+ FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions);
};
} // namespace statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index f45759b..1dcc8f9 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -27,54 +27,21 @@
using std::unordered_map;
SimpleConditionTracker::SimpleConditionTracker(
- const ConfigKey& key, const int64_t& id, const int index,
+ const ConfigKey& key, const int64_t& id, const uint64_t protoHash, const int index,
const SimplePredicate& simplePredicate,
- const unordered_map<int64_t, int>& trackerNameIndexMap)
- : ConditionTracker(id, index), mConfigKey(key), mContainANYPositionInInternalDimensions(false) {
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap)
+ : ConditionTracker(id, index, protoHash),
+ mConfigKey(key),
+ mContainANYPositionInInternalDimensions(false) {
VLOG("creating SimpleConditionTracker %lld", (long long)mConditionId);
mCountNesting = simplePredicate.count_nesting();
- if (simplePredicate.has_start()) {
- auto pair = trackerNameIndexMap.find(simplePredicate.start());
- if (pair == trackerNameIndexMap.end()) {
- ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
- return;
- }
- mStartLogMatcherIndex = pair->second;
- mTrackerIndex.insert(mStartLogMatcherIndex);
- } else {
- mStartLogMatcherIndex = -1;
- }
-
- if (simplePredicate.has_stop()) {
- auto pair = trackerNameIndexMap.find(simplePredicate.stop());
- if (pair == trackerNameIndexMap.end()) {
- ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop());
- return;
- }
- mStopLogMatcherIndex = pair->second;
- mTrackerIndex.insert(mStopLogMatcherIndex);
- } else {
- mStopLogMatcherIndex = -1;
- }
-
- if (simplePredicate.has_stop_all()) {
- auto pair = trackerNameIndexMap.find(simplePredicate.stop_all());
- if (pair == trackerNameIndexMap.end()) {
- ALOGW("Stop all matcher %lld found in the config", (long long)simplePredicate.stop_all());
- return;
- }
- mStopAllLogMatcherIndex = pair->second;
- mTrackerIndex.insert(mStopAllLogMatcherIndex);
- } else {
- mStopAllLogMatcherIndex = -1;
- }
+ setMatcherIndices(simplePredicate, atomMatchingTrackerMap);
if (simplePredicate.has_dimensions()) {
translateFieldMatcher(simplePredicate.dimensions(), &mOutputDimensions);
if (mOutputDimensions.size() > 0) {
mSliced = true;
- mDimensionTag = mOutputDimensions[0].mMatcher.getTag();
}
mContainANYPositionInInternalDimensions = HasPositionANY(simplePredicate.dimensions());
}
@@ -106,6 +73,59 @@
return mInitialized;
}
+bool SimpleConditionTracker::onConfigUpdated(
+ const vector<Predicate>& allConditionProtos, const int index,
+ const vector<sp<ConditionTracker>>& allConditionTrackers,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const unordered_map<int64_t, int>& conditionTrackerMap) {
+ ConditionTracker::onConfigUpdated(allConditionProtos, index, allConditionTrackers,
+ atomMatchingTrackerMap, conditionTrackerMap);
+ setMatcherIndices(allConditionProtos[index].simple_predicate(), atomMatchingTrackerMap);
+ return true;
+}
+
+void SimpleConditionTracker::setMatcherIndices(
+ const SimplePredicate& simplePredicate,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
+ mTrackerIndex.clear();
+ if (simplePredicate.has_start()) {
+ auto pair = atomMatchingTrackerMap.find(simplePredicate.start());
+ if (pair == atomMatchingTrackerMap.end()) {
+ ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
+ return;
+ }
+ mStartLogMatcherIndex = pair->second;
+ mTrackerIndex.insert(mStartLogMatcherIndex);
+ } else {
+ mStartLogMatcherIndex = -1;
+ }
+
+ if (simplePredicate.has_stop()) {
+ auto pair = atomMatchingTrackerMap.find(simplePredicate.stop());
+ if (pair == atomMatchingTrackerMap.end()) {
+ ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop());
+ return;
+ }
+ mStopLogMatcherIndex = pair->second;
+ mTrackerIndex.insert(mStopLogMatcherIndex);
+ } else {
+ mStopLogMatcherIndex = -1;
+ }
+
+ if (simplePredicate.has_stop_all()) {
+ auto pair = atomMatchingTrackerMap.find(simplePredicate.stop_all());
+ if (pair == atomMatchingTrackerMap.end()) {
+ ALOGW("Stop all matcher %lld found in the config",
+ (long long)simplePredicate.stop_all());
+ return;
+ }
+ mStopAllLogMatcherIndex = pair->second;
+ mTrackerIndex.insert(mStopAllLogMatcherIndex);
+ } else {
+ mStopAllLogMatcherIndex = -1;
+ }
+}
+
void SimpleConditionTracker::dumpState() {
VLOG("%lld DUMP:", (long long)mConditionId);
for (const auto& pair : mSlicedConditionState) {
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index 1a9e35e..7a8b4010 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -27,11 +27,11 @@
namespace os {
namespace statsd {
-class SimpleConditionTracker : public virtual ConditionTracker {
+class SimpleConditionTracker : public ConditionTracker {
public:
- SimpleConditionTracker(const ConfigKey& key, const int64_t& id, const int index,
- const SimplePredicate& simplePredicate,
- const std::unordered_map<int64_t, int>& trackerNameIndexMap);
+ SimpleConditionTracker(const ConfigKey& key, const int64_t& id, const uint64_t protoHash,
+ const int index, const SimplePredicate& simplePredicate,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap);
~SimpleConditionTracker();
@@ -40,6 +40,11 @@
const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
std::vector<ConditionState>& conditionCache) override;
+ bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index,
+ const std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const std::unordered_map<int64_t, int>& conditionTrackerMap) override;
+
void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
const std::vector<sp<ConditionTracker>>& mAllConditions,
@@ -112,10 +117,11 @@
std::set<HashableDimensionKey> mLastChangedToTrueDimensions;
std::set<HashableDimensionKey> mLastChangedToFalseDimensions;
- int mDimensionTag;
-
std::map<HashableDimensionKey, int> mSlicedConditionState;
+ void setMatcherIndices(const SimplePredicate& predicate,
+ const std::unordered_map<int64_t, int>& logTrackerMap);
+
void handleStopAll(std::vector<ConditionState>& conditionCache,
std::vector<bool>& changedCache);
@@ -129,6 +135,7 @@
FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedCondition);
FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim);
FRIEND_TEST(SimpleConditionTrackerTest, TestStopAll);
+ FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 5a52032..a0c701e 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -80,7 +80,7 @@
mConfigValid = initStatsdConfig(
key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
- mAllConditionTrackers, mAllMetricProducers, mAllAnomalyTrackers,
+ mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mAllAnomalyTrackers,
mAllPeriodicAlarmTrackers, mConditionToMetricMap, mTrackerToMetricMap,
mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
mDeactivationAtomTrackerToMetricMap, mAlertTrackerMap, mMetricIndexesWithActivation,
@@ -204,13 +204,20 @@
const sp<AlarmMonitor>& periodicAlarmMonitor) {
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
+ vector<sp<ConditionTracker>> newConditionTrackers;
+ unordered_map<int64_t, int> newConditionTrackerMap;
mTagIds.clear();
+ mTrackerToConditionMap.clear();
mConfigValid = updateStatsdConfig(
mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap, mTagIds,
- newAtomMatchingTrackers, newAtomMatchingTrackerMap);
+ timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
+ mAllConditionTrackers, mConditionTrackerMap, mTagIds, newAtomMatchingTrackers,
+ newAtomMatchingTrackerMap, newConditionTrackers, newConditionTrackerMap,
+ mTrackerToConditionMap);
mAllAtomMatchingTrackers = newAtomMatchingTrackers;
mAtomMatchingTrackerMap = newAtomMatchingTrackerMap;
+ mAllConditionTrackers = newConditionTrackers;
+ mConditionTrackerMap = newConditionTrackerMap;
return mConfigValid;
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 6f4b2d7..bd0c816 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -242,9 +242,12 @@
// To make updating configs faster, we map the id of a AtomMatchingTracker, MetricProducer, and
// ConditionTracker to its index in the corresponding vector.
- // Maps the id of an atom matcher to its index in mAllAtomMatchingTrackers.
+ // Maps the id of an atom matching tracker to its index in mAllAtomMatchingTrackers.
std::unordered_map<int64_t, int> mAtomMatchingTrackerMap;
+ // Maps the id of a condition tracker to its index in mAllConditionTrackers.
+ std::unordered_map<int64_t, int> mConditionTrackerMap;
+
// 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/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 9b684f1..dcfbd5e 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -411,7 +411,7 @@
void ValueMetricProducer::resetBase() {
for (auto& slice : mCurrentBaseInfo) {
- for (auto& baseInfo : slice.second) {
+ for (auto& baseInfo : slice.second.baseInfos) {
baseInfo.hasBase = false;
}
}
@@ -623,7 +623,7 @@
mMatchedMetricDimensionKeys.find(whatKey) != mMatchedMetricDimensionKeys.end();
if (!presentInPulledData && whatKey.contains(mStateChangePrimaryKey.second)) {
auto it = mCurrentBaseInfo.find(whatKey);
- for (auto& baseInfo : it->second) {
+ for (auto& baseInfo : it->second.baseInfos) {
baseInfo.hasBase = false;
}
}
@@ -652,7 +652,7 @@
(unsigned long)mCurrentSlicedBucket.size());
if (verbose) {
for (const auto& it : mCurrentSlicedBucket) {
- for (const auto& interval : it.second) {
+ for (const auto& interval : it.second.intervals) {
fprintf(out, "\t(what)%s\t(states)%s (value)%s\n",
it.first.getDimensionKeyInWhat().toString().c_str(),
it.first.getStateValuesKey().toString().c_str(),
@@ -788,23 +788,23 @@
return;
}
- vector<BaseInfo>& baseInfos = mCurrentBaseInfo[whatKey];
+ DimensionsInWhatInfo& dimensionsInWhatInfo = mCurrentBaseInfo[whatKey];
+ vector<BaseInfo>& baseInfos = dimensionsInWhatInfo.baseInfos;
if (baseInfos.size() < mFieldMatchers.size()) {
VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size());
baseInfos.resize(mFieldMatchers.size());
}
- for (BaseInfo& baseInfo : baseInfos) {
- if (!baseInfo.hasCurrentState) {
- baseInfo.currentState = getUnknownStateKey();
- baseInfo.hasCurrentState = true;
- }
+ if (!dimensionsInWhatInfo.hasCurrentState) {
+ dimensionsInWhatInfo.currentState = getUnknownStateKey();
+ dimensionsInWhatInfo.hasCurrentState = true;
}
// We need to get the intervals stored with the previous state key so we can
// close these value intervals.
- const auto oldStateKey = baseInfos[0].currentState;
- vector<Interval>& intervals = mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)];
+ const auto oldStateKey = dimensionsInWhatInfo.currentState;
+ vector<Interval>& intervals =
+ mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)].intervals;
if (intervals.size() < mFieldMatchers.size()) {
VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size());
intervals.resize(mFieldMatchers.size());
@@ -818,14 +818,14 @@
// Discussion here: http://ag/6124370.
bool useAnomalyDetection = true;
+ dimensionsInWhatInfo.hasCurrentState = true;
+ dimensionsInWhatInfo.currentState = stateKey;
for (int i = 0; i < (int)mFieldMatchers.size(); i++) {
const Matcher& matcher = mFieldMatchers[i];
BaseInfo& baseInfo = baseInfos[i];
Interval& interval = intervals[i];
interval.valueIndex = i;
Value value;
- baseInfo.hasCurrentState = true;
- baseInfo.currentState = stateKey;
if (!getDoubleOrLong(event, matcher, value)) {
VLOG("Failed to get value %d from event %s", i, event.ToString().c_str());
StatsdStats::getInstance().noteBadValueType(mMetricId);
@@ -990,7 +990,7 @@
bool bucketHasData = false;
// The current bucket is large enough to keep.
for (const auto& slice : mCurrentSlicedBucket) {
- ValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second);
+ PastValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second.intervals);
bucket.mConditionTrueNs = conditionTrueDuration;
// it will auto create new vector of ValuebucketInfo if the key is not found.
if (bucket.valueIndex.size() > 0) {
@@ -1030,9 +1030,9 @@
mCurrentBucketNum += numBucketsForward;
}
-ValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime,
- const std::vector<Interval>& intervals) {
- ValueBucket bucket;
+PastValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime,
+ const std::vector<Interval>& intervals) {
+ PastValueBucket bucket;
bucket.mBucketStartNs = mCurrentBucketStartTimeNs;
bucket.mBucketEndNs = bucketEndTime;
for (const auto& interval : intervals) {
@@ -1059,7 +1059,7 @@
// Cleanup data structure to aggregate values.
for (auto it = mCurrentSlicedBucket.begin(); it != mCurrentSlicedBucket.end();) {
bool obsolete = true;
- for (auto& interval : it->second) {
+ for (auto& interval : it->second.intervals) {
interval.hasValue = false;
interval.sampleSize = 0;
if (interval.seenNewData) {
@@ -1107,7 +1107,7 @@
continue;
}
// TODO: fix this when anomaly can accept double values
- auto& interval = slice.second[0];
+ auto& interval = slice.second.intervals[0];
if (interval.hasValue) {
mCurrentFullBucket[slice.first] += interval.value.long_value;
}
@@ -1126,7 +1126,7 @@
for (auto& tracker : mAnomalyTrackers) {
if (tracker != nullptr) {
// TODO: fix this when anomaly can accept double values
- auto& interval = slice.second[0];
+ auto& interval = slice.second.intervals[0];
if (interval.hasValue) {
tracker->addPastBucket(slice.first, interval.value.long_value,
mCurrentBucketNum);
@@ -1139,7 +1139,7 @@
// Accumulate partial bucket.
for (const auto& slice : mCurrentSlicedBucket) {
// TODO: fix this when anomaly can accept double values
- auto& interval = slice.second[0];
+ auto& interval = slice.second.intervals[0];
if (interval.hasValue) {
mCurrentFullBucket[slice.first] += interval.value.long_value;
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index e72002e..472cc33 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -31,7 +31,7 @@
namespace os {
namespace statsd {
-struct ValueBucket {
+struct PastValueBucket {
int64_t mBucketStartNs;
int64_t mBucketEndNs;
std::vector<int> valueIndex;
@@ -41,7 +41,6 @@
int64_t mConditionTrueNs;
};
-
// Aggregates values within buckets.
//
// There are different events that might complete a bucket
@@ -173,7 +172,7 @@
// if this is pulled metric
const bool mIsPulled;
- // internal state of an ongoing aggregation bucket.
+ // Tracks the value information of one value field.
typedef struct {
// Index in multi value aggregation.
int valueIndex;
@@ -188,25 +187,40 @@
bool seenNewData = false;
} Interval;
+ // Internal state of an ongoing aggregation bucket.
+ typedef struct CurrentValueBucket {
+ // Value information for each value field of the metric.
+ std::vector<Interval> intervals;
+ } CurrentValueBucket;
+
+ // Holds base information for diffing values from one value field.
typedef struct {
// Holds current base value of the dimension. Take diff and update if necessary.
Value base;
// Whether there is a base to diff to.
bool hasBase;
+ } BaseInfo;
+
+ // State key and base information for a specific DimensionsInWhat key.
+ typedef struct {
+ std::vector<BaseInfo> baseInfos;
// Last seen state value(s).
HashableDimensionKey currentState;
// Whether this dimensions in what key has a current state key.
bool hasCurrentState;
- } BaseInfo;
+ } DimensionsInWhatInfo;
- std::unordered_map<MetricDimensionKey, std::vector<Interval>> mCurrentSlicedBucket;
+ // Tracks the internal state in the ongoing aggregation bucket for each DimensionsInWhat
+ // key and StateValuesKey pair.
+ std::unordered_map<MetricDimensionKey, CurrentValueBucket> mCurrentSlicedBucket;
- std::unordered_map<HashableDimensionKey, std::vector<BaseInfo>> mCurrentBaseInfo;
+ // Tracks current state key and base information for each DimensionsInWhat key.
+ std::unordered_map<HashableDimensionKey, DimensionsInWhatInfo> mCurrentBaseInfo;
std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
- std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>> mPastBuckets;
+ std::unordered_map<MetricDimensionKey, std::vector<PastValueBucket>> mPastBuckets;
const int64_t mMinBucketSizeNs;
@@ -224,8 +238,8 @@
void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
int64_t originalPullTimeNs, int64_t eventElapsedTimeNs);
- ValueBucket buildPartialBucket(int64_t bucketEndTime,
- const std::vector<Interval>& intervals);
+ PastValueBucket buildPartialBucket(int64_t bucketEndTime,
+ const std::vector<Interval>& intervals);
void initCurrentSlicedBucket(int64_t nextBucketStartTimeNs);
@@ -234,7 +248,7 @@
// Reset diff base and mHasGlobalBase
void resetBase();
- static const size_t kBucketSize = sizeof(ValueBucket{});
+ static const size_t kBucketSize = sizeof(PastValueBucket{});
const size_t mDimensionSoftLimit;
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
index 0983dc0..bd60b6b 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
@@ -15,6 +15,7 @@
*/
#define DEBUG false // STOPSHIP if true
+#include "Log.h"
#include "config_update_utils.h"
@@ -44,7 +45,7 @@
// Check if new matcher.
const auto& oldAtomMatchingTrackerIt = oldAtomMatchingTrackerMap.find(id);
if (oldAtomMatchingTrackerIt == oldAtomMatchingTrackerMap.end()) {
- matchersToUpdate[matcherIdx] = UPDATE_REPLACE;
+ matchersToUpdate[matcherIdx] = UPDATE_NEW;
return true;
}
@@ -103,11 +104,13 @@
return true;
}
-bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
- const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
- const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
- set<int>& allTagIds, unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
- vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers) {
+bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
+ const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
+ set<int>& allTagIds,
+ unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
+ vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
+ set<int64_t>& replacedMatchers) {
const int atomMatcherCount = config.atom_matcher_size();
vector<AtomMatcher> matcherProtos;
@@ -157,7 +160,10 @@
newAtomMatchingTrackers.push_back(tracker);
break;
}
- case UPDATE_REPLACE: {
+ case UPDATE_REPLACE:
+ replacedMatchers.insert(id);
+ [[fallthrough]]; // Intentionally fallthrough to create the new matcher.
+ case UPDATE_NEW: {
sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(matcher, i, uidMap);
if (tracker == nullptr) {
return false;
@@ -187,6 +193,207 @@
return true;
}
+// Recursive function to determine if a condition needs to be updated. Populates conditionsToUpdate.
+// Returns whether the function was successful or not.
+bool determineConditionUpdateStatus(const StatsdConfig& config, const int conditionIdx,
+ const unordered_map<int64_t, int>& oldConditionTrackerMap,
+ const vector<sp<ConditionTracker>>& oldConditionTrackers,
+ const unordered_map<int64_t, int>& newConditionTrackerMap,
+ const set<int64_t>& replacedMatchers,
+ vector<UpdateStatus>& conditionsToUpdate,
+ vector<bool>& cycleTracker) {
+ // Have already examined this condition.
+ if (conditionsToUpdate[conditionIdx] != UPDATE_UNKNOWN) {
+ return true;
+ }
+
+ const Predicate& predicate = config.predicate(conditionIdx);
+ int64_t id = predicate.id();
+ // Check if new condition.
+ const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id);
+ if (oldConditionTrackerIt == oldConditionTrackerMap.end()) {
+ conditionsToUpdate[conditionIdx] = UPDATE_NEW;
+ return true;
+ }
+
+ // This is an existing condition. Check if it has changed.
+ string serializedCondition;
+ if (!predicate.SerializeToString(&serializedCondition)) {
+ ALOGE("Unable to serialize matcher %lld", (long long)id);
+ return false;
+ }
+ uint64_t newProtoHash = Hash64(serializedCondition);
+ if (newProtoHash != oldConditionTrackers[oldConditionTrackerIt->second]->getProtoHash()) {
+ conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
+ return true;
+ }
+
+ switch (predicate.contents_case()) {
+ case Predicate::ContentsCase::kSimplePredicate: {
+ // Need to check if any of the underlying matchers changed.
+ const SimplePredicate& simplePredicate = predicate.simple_predicate();
+ if (simplePredicate.has_start()) {
+ if (replacedMatchers.find(simplePredicate.start()) != replacedMatchers.end()) {
+ conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
+ return true;
+ }
+ }
+ if (simplePredicate.has_stop()) {
+ if (replacedMatchers.find(simplePredicate.stop()) != replacedMatchers.end()) {
+ conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
+ return true;
+ }
+ }
+ if (simplePredicate.has_stop_all()) {
+ if (replacedMatchers.find(simplePredicate.stop_all()) != replacedMatchers.end()) {
+ conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
+ return true;
+ }
+ }
+ conditionsToUpdate[conditionIdx] = UPDATE_PRESERVE;
+ return true;
+ }
+ case Predicate::ContentsCase::kCombination: {
+ // Need to recurse on the children to see if any of the child predicates changed.
+ cycleTracker[conditionIdx] = true;
+ UpdateStatus status = UPDATE_PRESERVE;
+ for (const int64_t childPredicateId : predicate.combination().predicate()) {
+ const auto& childIt = newConditionTrackerMap.find(childPredicateId);
+ if (childIt == newConditionTrackerMap.end()) {
+ ALOGW("Predicate %lld not found in the config", (long long)childPredicateId);
+ return false;
+ }
+ const int childIdx = childIt->second;
+ if (cycleTracker[childIdx]) {
+ ALOGE("Cycle detected in predicate config");
+ return false;
+ }
+ if (!determineConditionUpdateStatus(config, childIdx, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate,
+ cycleTracker)) {
+ return false;
+ }
+
+ if (conditionsToUpdate[childIdx] == UPDATE_REPLACE) {
+ status = UPDATE_REPLACE;
+ break;
+ }
+ }
+ conditionsToUpdate[conditionIdx] = status;
+ cycleTracker[conditionIdx] = false;
+ return true;
+ }
+ default: {
+ ALOGE("Predicate \"%lld\" malformed", (long long)id);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool updateConditions(const ConfigKey& key, const StatsdConfig& config,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const set<int64_t>& replacedMatchers,
+ const unordered_map<int64_t, int>& oldConditionTrackerMap,
+ const vector<sp<ConditionTracker>>& oldConditionTrackers,
+ unordered_map<int64_t, int>& newConditionTrackerMap,
+ vector<sp<ConditionTracker>>& newConditionTrackers,
+ unordered_map<int, vector<int>>& trackerToConditionMap,
+ vector<ConditionState>& conditionCache, set<int64_t>& replacedConditions) {
+ vector<Predicate> conditionProtos;
+ const int conditionTrackerCount = config.predicate_size();
+ conditionProtos.reserve(conditionTrackerCount);
+ newConditionTrackers.reserve(conditionTrackerCount);
+ conditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated);
+
+ for (int i = 0; i < conditionTrackerCount; i++) {
+ const Predicate& condition = config.predicate(i);
+ if (newConditionTrackerMap.find(condition.id()) != newConditionTrackerMap.end()) {
+ ALOGE("Duplicate Predicate found!");
+ return false;
+ }
+ newConditionTrackerMap[condition.id()] = i;
+ conditionProtos.push_back(condition);
+ }
+
+ vector<UpdateStatus> conditionsToUpdate(conditionTrackerCount, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(conditionTrackerCount, false);
+ for (int i = 0; i < conditionTrackerCount; i++) {
+ if (!determineConditionUpdateStatus(config, i, oldConditionTrackerMap, oldConditionTrackers,
+ newConditionTrackerMap, replacedMatchers,
+ conditionsToUpdate, cycleTracker)) {
+ return false;
+ }
+ }
+
+ // Update status has been determined for all conditions. Now perform the update.
+ set<int> preservedConditions;
+ for (int i = 0; i < conditionTrackerCount; i++) {
+ const Predicate& predicate = config.predicate(i);
+ const int64_t id = predicate.id();
+ switch (conditionsToUpdate[i]) {
+ case UPDATE_PRESERVE: {
+ preservedConditions.insert(i);
+ const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id);
+ if (oldConditionTrackerIt == oldConditionTrackerMap.end()) {
+ ALOGE("Could not find Predicate %lld in the previous config, but expected it "
+ "to be there",
+ (long long)id);
+ return false;
+ }
+ const int oldIndex = oldConditionTrackerIt->second;
+ newConditionTrackers.push_back(oldConditionTrackers[oldIndex]);
+ break;
+ }
+ case UPDATE_REPLACE:
+ replacedConditions.insert(id);
+ [[fallthrough]]; // Intentionally fallthrough to create the new condition tracker.
+ case UPDATE_NEW: {
+ sp<ConditionTracker> tracker =
+ createConditionTracker(key, predicate, i, atomMatchingTrackerMap);
+ if (tracker == nullptr) {
+ return false;
+ }
+ newConditionTrackers.push_back(tracker);
+ break;
+ }
+ default: {
+ ALOGE("Condition \"%lld\" update state is unknown. This should never happen",
+ (long long)id);
+ return false;
+ }
+ }
+ }
+
+ // Update indices of preserved predicates.
+ for (const int conditionIndex : preservedConditions) {
+ if (!newConditionTrackers[conditionIndex]->onConfigUpdated(
+ conditionProtos, conditionIndex, newConditionTrackers, atomMatchingTrackerMap,
+ newConditionTrackerMap)) {
+ ALOGE("Failed to update condition %lld",
+ (long long)newConditionTrackers[conditionIndex]->getConditionId());
+ return false;
+ }
+ }
+
+ std::fill(cycleTracker.begin(), cycleTracker.end(), false);
+ for (int conditionIndex = 0; conditionIndex < conditionTrackerCount; conditionIndex++) {
+ const sp<ConditionTracker>& conditionTracker = newConditionTrackers[conditionIndex];
+ // Calling init on preserved conditions is OK. It is needed to fill the condition cache.
+ if (!conditionTracker->init(conditionProtos, newConditionTrackers, newConditionTrackerMap,
+ cycleTracker, conditionCache)) {
+ return false;
+ }
+ for (const int trackerIndex : conditionTracker->getAtomMatchingTrackerIndex()) {
+ vector<int>& conditionList = trackerToConditionMap[trackerIndex];
+ conditionList.push_back(conditionIndex);
+ }
+ }
+ return true;
+}
+
bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
@@ -194,14 +401,34 @@
const int64_t currentTimeNs,
const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const vector<sp<ConditionTracker>>& oldConditionTrackers,
+ const unordered_map<int64_t, int>& oldConditionTrackerMap,
set<int>& allTagIds,
vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
- unordered_map<int64_t, int>& newAtomMatchingTrackerMap) {
- if (!updateAtomTrackers(config, uidMap, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers,
- allTagIds, newAtomMatchingTrackerMap, newAtomMatchingTrackers)) {
+ unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
+ vector<sp<ConditionTracker>>& newConditionTrackers,
+ unordered_map<int64_t, int>& newConditionTrackerMap,
+ unordered_map<int, vector<int>>& trackerToConditionMap) {
+ set<int64_t> replacedMatchers;
+ set<int64_t> replacedConditions;
+ vector<ConditionState> conditionCache;
+
+ if (!updateAtomMatchingTrackers(config, uidMap, oldAtomMatchingTrackerMap,
+ oldAtomMatchingTrackers, allTagIds, newAtomMatchingTrackerMap,
+ newAtomMatchingTrackers, replacedMatchers)) {
ALOGE("updateAtomMatchingTrackers failed");
return false;
}
+ VLOG("updateAtomMatchingTrackers succeeded");
+
+ if (!updateConditions(key, config, newAtomMatchingTrackerMap, replacedMatchers,
+ oldConditionTrackerMap, oldConditionTrackers, newConditionTrackerMap,
+ newConditionTrackers, trackerToConditionMap, conditionCache,
+ replacedConditions)) {
+ ALOGE("updateConditions failed");
+ return false;
+ }
+ VLOG("updateConditions succeeded");
return true;
}
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
index ae7b216..7ba684a 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
@@ -19,6 +19,7 @@
#include <vector>
#include "anomaly/AlarmMonitor.h"
+#include "condition/ConditionTracker.h"
#include "external/StatsPullerManager.h"
#include "matchers/AtomMatchingTracker.h"
@@ -31,30 +32,33 @@
// 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.
+// REPLACE means we should create a new one because the existing one changed
+// NEW means we should create a new one because one does not currently exist.
enum UpdateStatus {
UPDATE_UNKNOWN = 0,
UPDATE_PRESERVE = 1,
UPDATE_REPLACE = 2,
+ UPDATE_NEW = 3,
};
// 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
-// [newAtomMatchingTrackerMap]: matcher id to index mapping in the input StatsdConfig
// [oldAtomMatchingTrackerMap]: matcher id to index mapping in the existing MetricsManager
// [oldAtomMatchingTrackers]: stores the existing AtomMatchingTrackers
+// [newAtomMatchingTrackerMap]: matcher id to index mapping in the input StatsdConfig
// 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>& oldAtomMatchingTrackerMap,
- const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
- const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
- vector<UpdateStatus>& matchersToUpdate,
- vector<bool>& cycleTracker);
+// Returns whether the function was successful or not.
+bool determineMatcherUpdateStatus(
+ const StatsdConfig& config, const int matcherIdx,
+ const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
+ const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
+ std::vector<UpdateStatus>& matchersToUpdate, std::vector<bool>& cycleTracker);
// Updates the AtomMatchingTrackers.
// input:
@@ -64,12 +68,61 @@
// output:
// [allTagIds]: contains the set of all interesting tag ids to this config.
// [newAtomMatchingTrackerMap]: new matcher id to index mapping
-// [newAtomMatchers]: stores the new AtomMatchingTrackers
-bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
- const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
- const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
- set<int>& allTagIds, unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
- vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers);
+// [newAtomMatchingTrackers]: stores the new AtomMatchingTrackers
+// [replacedMatchers]: set of matcher ids that changed and have been replaced
+bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
+ const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
+ std::set<int>& allTagIds,
+ std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
+ std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
+ std::set<int64_t>& replacedMatchers);
+
+// Recursive function to determine if a condition needs to be updated.
+// input:
+// [config]: the input StatsdConfig
+// [conditionIdx]: the index of the current condition to be updated
+// [oldConditionTrackerMap]: condition id to index mapping in the existing MetricsManager
+// [oldConditionTrackers]: stores the existing ConditionTrackers
+// [newConditionTrackerMap]: condition id to index mapping in the input StatsdConfig
+// [replacedMatchers]: set of replaced matcher ids. conditions using these matchers must be replaced
+// output:
+// [conditionsToUpdate]: vector of the update status of each condition. The conditionIdx index will
+// be updated from UPDATE_UNKNOWN after this call.
+// [cycleTracker]: intermediate param used during recursion.
+// Returns whether the function was successful or not.
+bool determineConditionUpdateStatus(const StatsdConfig& config, const int conditionIdx,
+ const std::unordered_map<int64_t, int>& oldConditionTrackerMap,
+ const std::vector<sp<ConditionTracker>>& oldConditionTrackers,
+ const std::unordered_map<int64_t, int>& newConditionTrackerMap,
+ const std::set<int64_t>& replacedMatchers,
+ std::vector<UpdateStatus>& conditionsToUpdate,
+ std::vector<bool>& cycleTracker);
+
+// Updates ConditionTrackers
+// input:
+// [config]: the input config
+// [atomMatchingTrackerMap]: AtomMatchingTracker name to index mapping from previous step.
+// [replacedMatchers]: ids of replaced matchers. conditions depending on these must also be replaced
+// [oldConditionTrackerMap]: existing matcher id to index mapping
+// [oldConditionTrackers]: stores the existing ConditionTrackers
+// output:
+// [newConditionTrackerMap]: new condition id to index mapping
+// [newConditionTrackers]: stores the sp to all the ConditionTrackers
+// [trackerToConditionMap]: contains the mapping from the index of an atom matcher
+// to indices of condition trackers that use the matcher
+// [conditionCache]: stores the current conditions for each ConditionTracker
+// [replacedConditions]: set of matcher ids that have changed and have been replaced
+bool updateConditions(const ConfigKey& key, const StatsdConfig& config,
+ const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
+ const std::set<int64_t>& replacedMatchers,
+ const std::unordered_map<int64_t, int>& oldConditionTrackerMap,
+ const std::vector<sp<ConditionTracker>>& oldConditionTrackers,
+ std::unordered_map<int64_t, int>& newConditionTrackerMap,
+ std::vector<sp<ConditionTracker>>& newConditionTrackers,
+ std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
+ std::vector<ConditionState>& conditionCache,
+ std::set<int64_t>& replacedConditions);
// Updates the existing MetricsManager from a new StatsdConfig.
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
@@ -79,10 +132,15 @@
const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
const int64_t currentTimeNs,
const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
- const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
+ const std::vector<sp<ConditionTracker>>& oldConditionTrackers,
+ const std::unordered_map<int64_t, int>& oldConditionTrackerMap,
std::set<int>& allTagIds,
std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
- unordered_map<int64_t, int>& newAtomMatchingTrackerMap);
+ std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
+ std::vector<sp<ConditionTracker>>& newConditionTrackers,
+ std::unordered_map<int64_t, int>& newConditionTrackerMap,
+ std::unordered_map<int, std::vector<int>>& trackerToConditionMap);
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
index e40fbdb..2e3e434 100644
--- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
@@ -74,16 +74,37 @@
case AtomMatcher::ContentsCase::kSimpleAtomMatcher:
return new SimpleAtomMatchingTracker(logMatcher.id(), index, protoHash,
logMatcher.simple_atom_matcher(), uidMap);
- break;
case AtomMatcher::ContentsCase::kCombination:
return new CombinationAtomMatchingTracker(logMatcher.id(), index, protoHash);
- break;
default:
ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
return nullptr;
}
}
+sp<ConditionTracker> createConditionTracker(
+ const ConfigKey& key, const Predicate& predicate, const int index,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
+ string serializedPredicate;
+ if (!predicate.SerializeToString(&serializedPredicate)) {
+ ALOGE("Unable to serialize predicate %lld", (long long)predicate.id());
+ return nullptr;
+ }
+ uint64_t protoHash = Hash64(serializedPredicate);
+ switch (predicate.contents_case()) {
+ case Predicate::ContentsCase::kSimplePredicate: {
+ return new SimpleConditionTracker(key, predicate.id(), protoHash, index,
+ predicate.simple_predicate(), atomMatchingTrackerMap);
+ }
+ case Predicate::ContentsCase::kCombination: {
+ return new CombinationConditionTracker(predicate.id(), index, protoHash);
+ }
+ default:
+ ALOGE("Predicate \"%lld\" malformed", (long long)predicate.id());
+ return nullptr;
+ }
+}
+
bool handleMetricWithAtomMatchingTrackers(
const int64_t what, const int metricIndex, const bool usedForDimension,
const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
@@ -266,8 +287,7 @@
for (int i = 0; i < atomMatcherCount; i++) {
const AtomMatcher& logMatcher = config.atom_matcher(i);
- int index = allAtomMatchingTrackers.size();
- sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(logMatcher, index, uidMap);
+ sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(logMatcher, i, uidMap);
if (tracker == nullptr) {
return false;
}
@@ -276,7 +296,7 @@
ALOGE("Duplicate AtomMatcher found!");
return false;
}
- atomMatchingTrackerMap[logMatcher.id()] = index;
+ atomMatchingTrackerMap[logMatcher.id()] = i;
matcherConfigs.push_back(logMatcher);
}
@@ -307,28 +327,17 @@
for (int i = 0; i < conditionTrackerCount; i++) {
const Predicate& condition = config.predicate(i);
- int index = allConditionTrackers.size();
- switch (condition.contents_case()) {
- case Predicate::ContentsCase::kSimplePredicate: {
- allConditionTrackers.push_back(new SimpleConditionTracker(
- key, condition.id(), index, condition.simple_predicate(),
- atomMatchingTrackerMap));
- break;
- }
- case Predicate::ContentsCase::kCombination: {
- allConditionTrackers.push_back(
- new CombinationConditionTracker(condition.id(), index));
- break;
- }
- default:
- ALOGE("Predicate \"%lld\" malformed", (long long)condition.id());
- return false;
+ sp<ConditionTracker> tracker =
+ createConditionTracker(key, condition, i, atomMatchingTrackerMap);
+ if (tracker == nullptr) {
+ return false;
}
+ allConditionTrackers.push_back(tracker);
if (conditionTrackerMap.find(condition.id()) != conditionTrackerMap.end()) {
ALOGE("Duplicate Predicate found!");
return false;
}
- conditionTrackerMap[condition.id()] = index;
+ conditionTrackerMap[condition.id()] = i;
conditionConfigs.push_back(condition);
}
@@ -934,6 +943,7 @@
vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
unordered_map<int64_t, int>& atomMatchingTrackerMap,
vector<sp<ConditionTracker>>& allConditionTrackers,
+ unordered_map<int64_t, int>& conditionTrackerMap,
vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
@@ -944,7 +954,6 @@
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> conditionTrackerMap;
vector<ConditionState> initialConditionCache;
unordered_map<int64_t, int> metricProducerMap;
unordered_map<int64_t, int> stateAtomIdMap;
diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h
index 4cfd1b0..6eabcf4 100644
--- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h
@@ -42,6 +42,17 @@
sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher, const int index,
const sp<UidMap>& uidMap);
+// Create a ConditionTracker.
+// input:
+// [predicate]: the input Predicate from the StatsdConfig
+// [index]: the index of the condition tracker
+// [atomMatchingTrackerMap]: map of atom matcher id to its index in allAtomMatchingTrackers
+// output:
+// new ConditionTracker, or null if the tracker is unable to be created
+sp<ConditionTracker> createConditionTracker(
+ const ConfigKey& key, const Predicate& predicate, const int index,
+ const unordered_map<int64_t, int>& atomMatchingTrackerMap);
+
// Helper functions for MetricsManager to initialize from StatsdConfig.
// *Note*: only initStatsdConfig() should be called from outside.
// All other functions are intermediate
@@ -77,7 +88,6 @@
std::unordered_map<int64_t, int>& conditionTrackerMap,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
- std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks,
std::vector<ConditionState>& initialConditionCache);
// Initialize State maps using State protos in the config. These maps will
@@ -111,7 +121,6 @@
const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
const std::unordered_map<int64_t, int>& conditionTrackerMap,
- const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks,
const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
const unordered_map<int64_t, int>& stateAtomIdMap,
const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
@@ -135,6 +144,7 @@
std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
+ std::unordered_map<int64_t, int>& conditionTrackerMap,
std::vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 07b5311b..8998b5f 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -39,6 +39,7 @@
const int ATTRIBUTION_NODE_FIELD_ID = 1;
const int ATTRIBUTION_UID_FIELD_ID = 1;
const int TAG_ID = 1;
+const uint64_t protoHash = 0x123456789;
SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
bool outputSlicedUid, Position position) {
@@ -123,7 +124,7 @@
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
0 /*tracker index*/, simplePredicate,
trackerNameIndexMap);
@@ -177,7 +178,7 @@
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
0 /*tracker index*/, simplePredicate,
trackerNameIndexMap);
@@ -231,8 +232,9 @@
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), 0 /*tracker index*/,
- simplePredicate, trackerNameIndexMap);
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
+ 0 /*tracker index*/, simplePredicate,
+ trackerNameIndexMap);
EXPECT_FALSE(conditionTracker.isSliced());
// This event is not accessed in this test besides dimensions which is why this is okay.
@@ -317,7 +319,7 @@
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
EXPECT_FALSE(conditionTracker.isSliced());
@@ -392,7 +394,7 @@
trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
@@ -514,7 +516,7 @@
trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
@@ -610,7 +612,7 @@
trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
- SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 1000aea..8790fe4 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -57,7 +57,7 @@
double epsilon = 0.001;
static void assertPastBucketValuesSingleKey(
- const std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>>& mPastBuckets,
+ const std::unordered_map<MetricDimensionKey, std::vector<PastValueBucket>>& mPastBuckets,
const std::initializer_list<int>& expectedValuesList,
const std::initializer_list<int64_t>& expectedDurationNsList,
const std::initializer_list<int64_t>& expectedStartTimeNsList,
@@ -79,7 +79,7 @@
ASSERT_EQ(1, mPastBuckets.size());
ASSERT_EQ(expectedValues.size(), mPastBuckets.begin()->second.size());
- const vector<ValueBucket>& buckets = mPastBuckets.begin()->second;
+ const vector<PastValueBucket>& buckets = mPastBuckets.begin()->second;
for (int i = 0; i < expectedValues.size(); i++) {
EXPECT_EQ(expectedValues[i], buckets[i].values[0].long_value)
<< "Values differ at index " << i;
@@ -288,8 +288,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
@@ -304,8 +305,8 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(23, curBaseInfo.base.long_value);
@@ -322,8 +323,8 @@
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(36, curBaseInfo.base.long_value);
@@ -426,8 +427,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
@@ -455,8 +457,8 @@
allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 3, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// the base was reset
EXPECT_EQ(true, curBaseInfo.hasBase);
@@ -489,8 +491,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
@@ -502,8 +505,8 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -516,8 +519,8 @@
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -549,8 +552,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(11, curBaseInfo.base.long_value);
@@ -562,8 +566,8 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -573,8 +577,8 @@
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -624,8 +628,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// startUpdated:false sum:0 start:100
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
@@ -641,8 +646,8 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(110, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -654,8 +659,8 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(20, curInterval.value.long_value);
EXPECT_EQ(false, curBaseInfo.hasBase);
@@ -879,8 +884,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -888,7 +894,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(30, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
@@ -925,8 +931,8 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(20, curInterval.value.long_value);
LogEvent event3(/*uid=*/0, /*pid=*/0);
@@ -935,7 +941,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(50, curInterval.value.long_value);
valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35);
@@ -946,7 +952,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(50, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
@@ -1089,8 +1095,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// startUpdated:true sum:0 start:11
EXPECT_EQ(true, curBaseInfo.hasBase);
@@ -1104,8 +1111,8 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// tartUpdated:false sum:12
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(23, curBaseInfo.base.long_value);
@@ -1121,8 +1128,8 @@
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket6StartTimeNs + 1, 36));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// startUpdated:false sum:12
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(36, curBaseInfo.base.long_value);
@@ -1180,8 +1187,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1189,8 +1197,8 @@
// pull on bucket boundary come late, condition change happens before it
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
EXPECT_EQ(false, curBaseInfo.hasBase);
@@ -1203,8 +1211,8 @@
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
}
@@ -1252,8 +1260,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// startUpdated:false sum:0 start:100
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
@@ -1265,8 +1274,8 @@
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1274,8 +1283,8 @@
valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(130, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1286,8 +1295,8 @@
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 50, 140));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 50);
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(140, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1327,7 +1336,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1335,7 +1344,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(10, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
@@ -1364,7 +1373,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1374,7 +1383,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(20, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
@@ -1405,7 +1414,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval;
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(1, curInterval.sampleSize);
@@ -1414,7 +1423,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(25, curInterval.value.long_value);
EXPECT_EQ(2, curInterval.sampleSize);
@@ -1449,7 +1458,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1457,7 +1466,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(25, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
@@ -1487,8 +1496,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1499,7 +1509,7 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(5, curInterval.value.long_value);
@@ -1509,8 +1519,8 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(15, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1520,8 +1530,8 @@
CreateRepeatedValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 15);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(15, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1558,12 +1568,13 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(20, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1572,12 +1583,12 @@
// has one slice
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(5, curInterval.value.long_value);
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(2, curInterval.value.long_value);
@@ -1587,14 +1598,14 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(15, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(25, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1604,13 +1615,13 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(15, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
- curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(29, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1656,9 +1667,9 @@
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
auto iter = valueProducer->mCurrentSlicedBucket.begin();
- auto& interval1 = iter->second[0];
+ auto& interval1 = iter->second.intervals[0];
auto iterBase = valueProducer->mCurrentBaseInfo.begin();
- auto& baseInfo1 = iterBase->second[0];
+ auto& baseInfo1 = iterBase->second.baseInfos[0];
EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo1.hasBase);
EXPECT_EQ(3, baseInfo1.base.long_value);
@@ -1692,8 +1703,8 @@
}
EXPECT_TRUE(it != iter);
EXPECT_TRUE(itBase != iterBase);
- auto& interval2 = it->second[0];
- auto& baseInfo2 = itBase->second[0];
+ auto& interval2 = it->second.intervals[0];
+ auto& baseInfo2 = itBase->second.baseInfos[0];
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo2.hasBase);
EXPECT_EQ(4, baseInfo2.base.long_value);
@@ -1732,9 +1743,10 @@
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
const auto& it = valueProducer->mCurrentSlicedBucket.begin();
- ValueMetricProducer::Interval& interval1 = it->second[0];
+ ValueMetricProducer::Interval& interval1 = it->second.intervals[0];
ValueMetricProducer::BaseInfo& baseInfo1 =
- valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0];
+ valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())
+ ->second.baseInfos[0];
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo1.hasBase);
EXPECT_EQ(3, baseInfo1.base.long_value);
@@ -1761,9 +1773,10 @@
}
}
EXPECT_TRUE(it2 != it);
- ValueMetricProducer::Interval& interval2 = it2->second[0];
+ ValueMetricProducer::Interval& interval2 = it2->second.intervals[0];
ValueMetricProducer::BaseInfo& baseInfo2 =
- valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
+ valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())
+ ->second.baseInfos[0];
EXPECT_EQ(2, it2->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo2.hasBase);
EXPECT_EQ(4, baseInfo2.base.long_value);
@@ -1792,14 +1805,16 @@
// Get new references now that entries have been deleted from the map
const auto& it3 = valueProducer->mCurrentSlicedBucket.begin();
const auto& it4 = std::next(valueProducer->mCurrentSlicedBucket.begin());
- ASSERT_EQ(it3->second.size(), 1);
- ASSERT_EQ(it4->second.size(), 1);
- ValueMetricProducer::Interval& interval3 = it3->second[0];
- ValueMetricProducer::Interval& interval4 = it4->second[0];
+ ASSERT_EQ(it3->second.intervals.size(), 1);
+ ASSERT_EQ(it4->second.intervals.size(), 1);
+ ValueMetricProducer::Interval& interval3 = it3->second.intervals[0];
+ ValueMetricProducer::Interval& interval4 = it4->second.intervals[0];
ValueMetricProducer::BaseInfo& baseInfo3 =
- valueProducer->mCurrentBaseInfo.find(it3->first.getDimensionKeyInWhat())->second[0];
+ valueProducer->mCurrentBaseInfo.find(it3->first.getDimensionKeyInWhat())
+ ->second.baseInfos[0];
ValueMetricProducer::BaseInfo& baseInfo4 =
- valueProducer->mCurrentBaseInfo.find(it4->first.getDimensionKeyInWhat())->second[0];
+ valueProducer->mCurrentBaseInfo.find(it4->first.getDimensionKeyInWhat())
+ ->second.baseInfos[0];
EXPECT_EQ(true, baseInfo3.hasBase);
EXPECT_EQ(5, baseInfo3.base.long_value);
@@ -1837,9 +1852,9 @@
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
auto iter = valueProducer->mCurrentSlicedBucket.begin();
- auto& interval1 = iter->second[0];
+ auto& interval1 = iter->second.intervals[0];
auto iterBase = valueProducer->mCurrentBaseInfo.begin();
- auto& baseInfo1 = iterBase->second[0];
+ auto& baseInfo1 = iterBase->second.baseInfos[0];
EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo1.hasBase);
EXPECT_EQ(3, baseInfo1.base.long_value);
@@ -1875,8 +1890,8 @@
}
EXPECT_TRUE(it != iter);
EXPECT_TRUE(itBase != iterBase);
- auto interval2 = it->second[0];
- auto baseInfo2 = itBase->second[0];
+ auto interval2 = it->second.intervals[0];
+ auto baseInfo2 = itBase->second.baseInfos[0];
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo2.hasBase);
EXPECT_EQ(4, baseInfo2.base.long_value);
@@ -1889,8 +1904,8 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
// Only one interval left. One was trimmed.
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ interval2 = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, baseInfo2.hasBase);
EXPECT_EQ(5, baseInfo2.base.long_value);
@@ -1903,8 +1918,8 @@
allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 2, 14));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
- interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ interval2 = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, baseInfo2.hasBase);
EXPECT_EQ(14, baseInfo2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
@@ -1943,8 +1958,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo& curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1980,8 +1996,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo& curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -2030,8 +2047,9 @@
valueProducer->onConditionChanged(false, bucketStartTimeNs + 1);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
@@ -2103,8 +2121,9 @@
valueProducer->mHasGlobalBase = true;
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -2156,8 +2175,9 @@
// Contains base from last pull which was successful.
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(140, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -2294,8 +2314,9 @@
// Contains base from last pull which was successful.
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(140, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -2373,8 +2394,9 @@
// Last pull failed so base has been reset.
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
@@ -2460,8 +2482,9 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
@@ -2469,8 +2492,8 @@
// Empty pull.
valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
@@ -2513,8 +2536,9 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 12);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
@@ -2524,8 +2548,8 @@
allData.clear();
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
// Data is empty, base should be reset.
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(5, curBaseInfo.base.long_value);
@@ -2570,14 +2594,14 @@
ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
auto iterator = valueProducer->mCurrentSlicedBucket.begin();
auto baseInfoIter = valueProducer->mCurrentBaseInfo.begin();
- EXPECT_EQ(true, baseInfoIter->second[0].hasBase);
- EXPECT_EQ(2, baseInfoIter->second[0].base.long_value);
- EXPECT_EQ(false, iterator->second[0].hasValue);
+ EXPECT_EQ(true, baseInfoIter->second.baseInfos[0].hasBase);
+ EXPECT_EQ(2, baseInfoIter->second.baseInfos[0].base.long_value);
+ EXPECT_EQ(false, iterator->second.intervals[0].hasValue);
iterator++;
baseInfoIter++;
- EXPECT_EQ(false, baseInfoIter->second[0].hasBase);
- EXPECT_EQ(1, baseInfoIter->second[0].base.long_value);
- EXPECT_EQ(false, iterator->second[0].hasValue);
+ EXPECT_EQ(false, baseInfoIter->second.baseInfos[0].hasBase);
+ EXPECT_EQ(1, baseInfoIter->second.baseInfos[0].base.long_value);
+ EXPECT_EQ(false, iterator->second.intervals[0].hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
}
@@ -2676,8 +2700,8 @@
valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(5, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -2811,8 +2835,8 @@
valueProducer->onConditionChanged(false, bucketStartTimeNs + 12);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(2, curInterval.value.long_value);
@@ -3045,8 +3069,9 @@
// has one slice
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(20, curInterval.value.long_value);
@@ -3058,8 +3083,8 @@
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {50 - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
- curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
}
@@ -3091,8 +3116,9 @@
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs - 8},
{bucketStartTimeNs}, {bucket2StartTimeNs});
ValueMetricProducer::Interval curInterval =
- valueProducer->mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
+ ValueMetricProducer::BaseInfo curBaseInfo =
+ valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
}
@@ -3984,18 +4010,18 @@
// Base for dimension key {}
auto it = valueProducer->mCurrentSlicedBucket.begin();
auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(3, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, kStateUnknown}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after screen state change kStateUnknown->ON.
auto screenEvent = CreateScreenStateChangedEvent(
@@ -4005,19 +4031,19 @@
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(5, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, kStateUnknown}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Bucket status after screen state change ON->OFF.
screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10,
@@ -4027,26 +4053,26 @@
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(9, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, ON}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(4, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(4, it->second.intervals[0].value.long_value);
// Value for dimension, state key {{}, kStateUnknown}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Bucket status after screen state change OFF->ON.
screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15,
@@ -4056,35 +4082,35 @@
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(21, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(21, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, OFF}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(12, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(12, it->second.intervals[0].value.long_value);
// Value for dimension, state key {{}, ON}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(4, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(4, it->second.intervals[0].value.long_value);
// Value for dimension, state key {{}, kStateUnknown}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Start dump report and check output.
ProtoOutputStream output;
@@ -4195,18 +4221,18 @@
// Base for dimension key {}
auto it = valueProducer->mCurrentSlicedBucket.begin();
auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(3, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, {kStateUnknown}}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after screen state change kStateUnknown->ON.
auto screenEvent = CreateScreenStateChangedEvent(
@@ -4216,19 +4242,19 @@
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(5, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
- itBase->second[0].currentState.getValues()[0].mValue.long_value);
+ itBase->second.currentState.getValues()[0].mValue.long_value);
// Value for dimension, state key {{}, kStateUnknown}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Bucket status after screen state change ON->VR.
// Both ON and VR are in the same state group, so the base should not change.
@@ -4239,19 +4265,19 @@
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(5, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, kStateUnknown}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Bucket status after screen state change VR->ON.
// Both ON and VR are in the same state group, so the base should not change.
@@ -4262,19 +4288,19 @@
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(5, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, kStateUnknown}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Bucket status after screen state change VR->OFF.
screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15,
@@ -4284,27 +4310,27 @@
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(21, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(21, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOffGroup.group_id(),
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{}, ON GROUP}
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
it->first.getStateValuesKey().getValues()[0].mValue.long_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(16, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(16, it->second.intervals[0].value.long_value);
// Value for dimension, state key {{}, kStateUnknown}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Start dump report and check output.
ProtoOutputStream output;
@@ -4447,35 +4473,35 @@
// Base for dimension key {uid 1}.
auto it = valueProducer->mCurrentSlicedBucket.begin();
auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(3, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{uid 1}, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Base for dimension key {uid 2}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(7, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(7, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for dimension, state key {{uid 2}, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after uid 1 process state change kStateUnknown -> Foreground.
auto uidProcessEvent = CreateUidProcessStateChangedEvent(
@@ -4485,36 +4511,36 @@
// Base for dimension key {uid 1}.
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(6, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(6, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 1, kStateUnknown}.
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(3, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(3, it->second.intervals[0].value.long_value);
// Base for dimension key {uid 2}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(7, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(7, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 2, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after uid 2 process state change kStateUnknown -> Background.
uidProcessEvent = CreateUidProcessStateChangedEvent(
@@ -4524,36 +4550,36 @@
// Base for dimension key {uid 1}.
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(6, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(6, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 1, kStateUnknown}.
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(3, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(3, it->second.intervals[0].value.long_value);
// Base for dimension key {uid 2}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(9, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 2, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Pull at end of first bucket.
vector<shared_ptr<LogEvent>> allData;
@@ -4570,36 +4596,36 @@
it = valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(15, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 2, BACKGROUND}.
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Base for dimension key {uid 1}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(10, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(10, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 1, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* kStateTracker::kUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Value for key {uid 1, FOREGROUND}
it++;
@@ -4608,7 +4634,7 @@
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Value for key {uid 2, kStateUnknown}
it++;
@@ -4617,7 +4643,7 @@
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* kStateTracker::kUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after uid 1 process state change from Foreground -> Background.
uidProcessEvent = CreateUidProcessStateChangedEvent(
@@ -4630,35 +4656,35 @@
// Base for dimension key {uid 2}.
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(15, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 2, BACKGROUND}.
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Base for dimension key {uid 1}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(13, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(13, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 1, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Value for key {uid 1, FOREGROUND}
it++;
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4666,8 +4692,8 @@
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(3, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(3, it->second.intervals[0].value.long_value);
// Value for key {uid 2, kStateUnknown}
it++;
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4675,7 +4701,7 @@
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after uid 1 process state change Background->Foreground.
uidProcessEvent = CreateUidProcessStateChangedEvent(
@@ -4687,36 +4713,36 @@
// Base for dimension key {uid 2}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(15, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 2, BACKGROUND}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Base for dimension key {uid 1}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(17, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(17, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {uid 1, kStateUnknown}
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Value for key {uid 1, BACKGROUND}
it++;
@@ -4725,8 +4751,8 @@
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(4, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(4, it->second.intervals[0].value.long_value);
// Value for key {uid 1, FOREGROUND}
it++;
@@ -4735,8 +4761,8 @@
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(3, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(3, it->second.intervals[0].value.long_value);
// Value for key {uid 2, kStateUnknown}
it++;
@@ -4857,23 +4883,23 @@
valueProducer->onConditionChanged(true, bucketStartTimeNs + 20 * NS_PER_SEC);
// Base for dimension key {}
ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
- std::unordered_map<HashableDimensionKey, std::vector<ValueMetricProducer::BaseInfo>>::iterator
+ std::unordered_map<HashableDimensionKey, ValueMetricProducer::DimensionsInWhatInfo>::iterator
itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(3, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::ON,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {{}, -1}
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- std::unordered_map<MetricDimensionKey, std::vector<ValueMetricProducer::Interval>>::iterator
- it = valueProducer->mCurrentSlicedBucket.begin();
+ std::unordered_map<MetricDimensionKey, ValueMetricProducer::CurrentValueBucket>::iterator it =
+ valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_FALSE(it->second[0].hasValue);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
// Bucket status after battery saver mode OFF event.
unique_ptr<LogEvent> batterySaverOffEvent =
@@ -4882,12 +4908,12 @@
// Base for dimension key {}
ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(5, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::OFF,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {{}, ON}
ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
it = valueProducer->mCurrentSlicedBucket.begin();
@@ -4895,8 +4921,8 @@
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::ON,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(2, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(2, it->second.intervals[0].value.long_value);
// Pull at end of first bucket.
vector<shared_ptr<LogEvent>> allData;
@@ -4909,23 +4935,23 @@
// Base for dimension key {}
ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
- EXPECT_TRUE(itBase->second[0].hasBase);
- EXPECT_EQ(11, itBase->second[0].base.long_value);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(11, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::OFF,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Bucket 2 status after condition change to false.
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 10 * NS_PER_SEC);
// Base for dimension key {}
ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
- EXPECT_FALSE(itBase->second[0].hasBase);
- EXPECT_TRUE(itBase->second[0].hasCurrentState);
- ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_FALSE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::OFF,
- itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ itBase->second.currentState.getValues()[0].mValue.int_value);
// Value for key {{}, OFF}
ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
it = valueProducer->mCurrentSlicedBucket.begin();
@@ -4933,8 +4959,8 @@
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::OFF,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
- EXPECT_TRUE(it->second[0].hasValue);
- EXPECT_EQ(4, it->second[0].value.long_value);
+ EXPECT_TRUE(it->second.intervals[0].hasValue);
+ EXPECT_EQ(4, it->second.intervals[0].value.long_value);
// Start dump report and check output.
ProtoOutputStream output;
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
index 8c698eb..890884b 100644
--- a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
+++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
@@ -14,6 +14,7 @@
#include "src/metrics/parsing_utils/config_update_utils.h"
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
#include <stdio.h>
@@ -23,6 +24,8 @@
#include <vector>
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "src/condition/CombinationConditionTracker.h"
+#include "src/condition/SimpleConditionTracker.h"
#include "src/matchers/CombinationAtomMatchingTracker.h"
#include "src/metrics/parsing_utils/metrics_manager_util.h"
#include "tests/statsd_test_util.h"
@@ -53,6 +56,7 @@
vector<sp<AtomMatchingTracker>> oldAtomMatchingTrackers;
unordered_map<int64_t, int> oldAtomMatchingTrackerMap;
vector<sp<ConditionTracker>> oldConditionTrackers;
+unordered_map<int64_t, int> oldConditionTrackerMap;
vector<sp<MetricProducer>> oldMetricProducers;
std::vector<sp<AnomalyTracker>> oldAnomalyTrackers;
std::vector<sp<AlarmTracker>> oldAlarmTrackers;
@@ -75,6 +79,7 @@
oldAtomMatchingTrackers.clear();
oldAtomMatchingTrackerMap.clear();
oldConditionTrackers.clear();
+ oldConditionTrackerMap.clear();
oldMetricProducers.clear();
oldAnomalyTrackers.clear();
oldAlarmTrackers.clear();
@@ -93,8 +98,8 @@
return initStatsdConfig(
key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseNs, timeBaseNs, allTagIds, oldAtomMatchingTrackers, oldAtomMatchingTrackerMap,
- oldConditionTrackers, oldMetricProducers, oldAnomalyTrackers, oldAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ oldConditionTrackers, oldConditionTrackerMap, oldMetricProducers, oldAnomalyTrackers,
+ oldAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds);
}
@@ -144,6 +149,30 @@
EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE);
}
+TEST_F(ConfigUpdateTest, TestSimpleMatcherNew) {
+ StatsdConfig config;
+ AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10);
+ *config.add_atom_matcher() = matcher;
+
+ EXPECT_TRUE(initConfig(config));
+
+ StatsdConfig newConfig;
+ // Different id, so should be a new matcher.
+ AtomMatcher newMatcher = CreateSimpleAtomMatcher("DIFFERENT_NAME", /*atom=*/10);
+ int64_t matcherId = newMatcher.id();
+ EXPECT_NE(matcherId, matcher.id());
+ *newConfig.add_atom_matcher() = newMatcher;
+
+ vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(1, false);
+ unordered_map<int64_t, int> newAtomMatchingTrackerMap;
+ newAtomMatchingTrackerMap[matcherId] = 0;
+ EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 0, oldAtomMatchingTrackerMap,
+ oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
+ matchersToUpdate, cycleTracker));
+ EXPECT_EQ(matchersToUpdate[0], UPDATE_NEW);
+}
+
TEST_F(ConfigUpdateTest, TestCombinationMatcherPreserve) {
StatsdConfig config;
AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10);
@@ -338,9 +367,10 @@
set<int> newTagIds;
unordered_map<int64_t, int> newAtomMatchingTrackerMap;
vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
- EXPECT_TRUE(updateAtomTrackers(newConfig, uidMap, oldAtomMatchingTrackerMap,
- oldAtomMatchingTrackers, newTagIds, newAtomMatchingTrackerMap,
- newAtomMatchingTrackers));
+ set<int64_t> replacedMatchers;
+ EXPECT_TRUE(updateAtomMatchingTrackers(
+ newConfig, uidMap, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers, newTagIds,
+ newAtomMatchingTrackerMap, newAtomMatchingTrackers, replacedMatchers));
ASSERT_EQ(newTagIds.size(), 3);
EXPECT_EQ(newTagIds.count(10), 1);
@@ -405,8 +435,454 @@
EXPECT_EQ(childMatchers->size(), 2);
EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end());
EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 4), childMatchers->end());
+
+ // Expect replacedMatchers to have simple2 and combination2
+ ASSERT_EQ(replacedMatchers.size(), 2);
+ EXPECT_NE(replacedMatchers.find(simple2Id), replacedMatchers.end());
+ EXPECT_NE(replacedMatchers.find(combination2Id), replacedMatchers.end());
}
+TEST_F(ConfigUpdateTest, TestSimpleConditionPreserve) {
+ StatsdConfig config;
+ AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = startMatcher;
+ AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = stopMatcher;
+
+ Predicate predicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = predicate;
+
+ // Create an initial config.
+ EXPECT_TRUE(initConfig(config));
+
+ set<int64_t> replacedMatchers;
+ vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(1, false);
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ newConditionTrackerMap[predicate.id()] = 0;
+ EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE);
+}
+
+TEST_F(ConfigUpdateTest, TestSimpleConditionReplace) {
+ StatsdConfig config;
+ AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = startMatcher;
+ AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = stopMatcher;
+
+ Predicate predicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = predicate;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Modify the predicate.
+ config.mutable_predicate(0)->mutable_simple_predicate()->set_count_nesting(true);
+
+ set<int64_t> replacedMatchers;
+ vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(1, false);
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ newConditionTrackerMap[predicate.id()] = 0;
+ EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
+}
+
+TEST_F(ConfigUpdateTest, TestSimpleConditionDepsChange) {
+ StatsdConfig config;
+ AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
+ int64_t startMatcherId = startMatcher.id();
+ *config.add_atom_matcher() = startMatcher;
+ AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = stopMatcher;
+
+ Predicate predicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = predicate;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Start matcher was replaced.
+ set<int64_t> replacedMatchers;
+ replacedMatchers.insert(startMatcherId);
+
+ vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(1, false);
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ newConditionTrackerMap[predicate.id()] = 0;
+ EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
+}
+
+TEST_F(ConfigUpdateTest, TestCombinationConditionPreserve) {
+ StatsdConfig config;
+ AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOffMatcher;
+
+ Predicate simple1 = CreateScreenIsOnPredicate();
+ *config.add_predicate() = simple1;
+ Predicate simple2 = CreateScreenIsOffPredicate();
+ *config.add_predicate() = simple2;
+
+ Predicate combination1;
+ combination1.set_id(StringToId("COMBINATION1"));
+ Predicate_Combination* combinationInternal = combination1.mutable_combination();
+ combinationInternal->set_operation(LogicalOperation::NAND);
+ combinationInternal->add_predicate(simple1.id());
+ combinationInternal->add_predicate(simple2.id());
+ *config.add_predicate() = combination1;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Same predicates, different order
+ StatsdConfig newConfig;
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ *newConfig.add_predicate() = combination1;
+ newConditionTrackerMap[combination1.id()] = 0;
+ *newConfig.add_predicate() = simple2;
+ newConditionTrackerMap[simple2.id()] = 1;
+ *newConfig.add_predicate() = simple1;
+ newConditionTrackerMap[simple1.id()] = 2;
+
+ set<int64_t> replacedMatchers;
+ vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(3, false);
+ // Only update the combination. It should recurse the two child predicates and preserve all 3.
+ EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE);
+ EXPECT_EQ(conditionsToUpdate[1], UPDATE_PRESERVE);
+ EXPECT_EQ(conditionsToUpdate[2], UPDATE_PRESERVE);
+}
+
+TEST_F(ConfigUpdateTest, TestCombinationConditionReplace) {
+ StatsdConfig config;
+ AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOffMatcher;
+
+ Predicate simple1 = CreateScreenIsOnPredicate();
+ *config.add_predicate() = simple1;
+ Predicate simple2 = CreateScreenIsOffPredicate();
+ *config.add_predicate() = simple2;
+
+ Predicate combination1;
+ combination1.set_id(StringToId("COMBINATION1"));
+ Predicate_Combination* combinationInternal = combination1.mutable_combination();
+ combinationInternal->set_operation(LogicalOperation::NAND);
+ combinationInternal->add_predicate(simple1.id());
+ combinationInternal->add_predicate(simple2.id());
+ *config.add_predicate() = combination1;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Changing the logical operation changes the predicate definition, so it should be replaced.
+ combination1.mutable_combination()->set_operation(LogicalOperation::OR);
+
+ StatsdConfig newConfig;
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ *newConfig.add_predicate() = combination1;
+ newConditionTrackerMap[combination1.id()] = 0;
+ *newConfig.add_predicate() = simple2;
+ newConditionTrackerMap[simple2.id()] = 1;
+ *newConfig.add_predicate() = simple1;
+ newConditionTrackerMap[simple1.id()] = 2;
+
+ set<int64_t> replacedMatchers;
+ vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(3, false);
+ // Only update the combination. The simple conditions should not be evaluated.
+ EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
+ EXPECT_EQ(conditionsToUpdate[1], UPDATE_UNKNOWN);
+ EXPECT_EQ(conditionsToUpdate[2], UPDATE_UNKNOWN);
+}
+
+TEST_F(ConfigUpdateTest, TestCombinationConditionDepsChange) {
+ StatsdConfig config;
+ AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOffMatcher;
+
+ Predicate simple1 = CreateScreenIsOnPredicate();
+ *config.add_predicate() = simple1;
+ Predicate simple2 = CreateScreenIsOffPredicate();
+ *config.add_predicate() = simple2;
+
+ Predicate combination1;
+ combination1.set_id(StringToId("COMBINATION1"));
+ Predicate_Combination* combinationInternal = combination1.mutable_combination();
+ combinationInternal->set_operation(LogicalOperation::NAND);
+ combinationInternal->add_predicate(simple1.id());
+ combinationInternal->add_predicate(simple2.id());
+ *config.add_predicate() = combination1;
+
+ EXPECT_TRUE(initConfig(config));
+
+ simple2.mutable_simple_predicate()->set_count_nesting(false);
+
+ StatsdConfig newConfig;
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ *newConfig.add_predicate() = combination1;
+ newConditionTrackerMap[combination1.id()] = 0;
+ *newConfig.add_predicate() = simple2;
+ newConditionTrackerMap[simple2.id()] = 1;
+ *newConfig.add_predicate() = simple1;
+ newConditionTrackerMap[simple1.id()] = 2;
+
+ set<int64_t> replacedMatchers;
+ vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(3, false);
+ // Only update the combination. Simple2 and combination1 must be evaluated.
+ EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
+ oldConditionTrackers, newConditionTrackerMap,
+ replacedMatchers, conditionsToUpdate, cycleTracker));
+ EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
+ EXPECT_EQ(conditionsToUpdate[1], UPDATE_REPLACE);
+}
+
+TEST_F(ConfigUpdateTest, TestUpdateConditions) {
+ StatsdConfig config;
+
+ // Add atom matchers. These are mostly needed for initStatsdConfig
+ AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
+ int64_t matcher1Id = matcher1.id();
+ *config.add_atom_matcher() = matcher1;
+
+ AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
+ int64_t matcher2Id = matcher2.id();
+ *config.add_atom_matcher() = matcher2;
+
+ AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
+ int64_t matcher3Id = matcher3.id();
+ *config.add_atom_matcher() = matcher3;
+
+ AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher();
+ int64_t matcher4Id = matcher4.id();
+ *config.add_atom_matcher() = matcher4;
+
+ AtomMatcher matcher5 = CreateBatterySaverModeStartAtomMatcher();
+ int64_t matcher5Id = matcher5.id();
+ *config.add_atom_matcher() = matcher5;
+
+ AtomMatcher matcher6 = CreateBatterySaverModeStopAtomMatcher();
+ int64_t matcher6Id = matcher6.id();
+ *config.add_atom_matcher() = matcher6;
+
+ // Add the predicates.
+ // Will be preserved.
+ Predicate simple1 = CreateScreenIsOnPredicate();
+ int64_t simple1Id = simple1.id();
+ *config.add_predicate() = simple1;
+
+ // Will be preserved.
+ Predicate simple2 = CreateScheduledJobPredicate();
+ int64_t simple2Id = simple2.id();
+ *config.add_predicate() = simple2;
+
+ // Will be replaced.
+ Predicate simple3 = CreateBatterySaverModePredicate();
+ int64_t simple3Id = simple3.id();
+ *config.add_predicate() = simple3;
+
+ // Will be preserved
+ Predicate combination1;
+ combination1.set_id(StringToId("COMBINATION1"));
+ combination1.mutable_combination()->set_operation(LogicalOperation::AND);
+ combination1.mutable_combination()->add_predicate(simple1Id);
+ combination1.mutable_combination()->add_predicate(simple2Id);
+ int64_t combination1Id = combination1.id();
+ *config.add_predicate() = combination1;
+
+ // Will be replaced since simple3 will be replaced.
+ Predicate combination2;
+ combination2.set_id(StringToId("COMBINATION2"));
+ combination2.mutable_combination()->set_operation(LogicalOperation::OR);
+ combination2.mutable_combination()->add_predicate(simple1Id);
+ combination2.mutable_combination()->add_predicate(simple3Id);
+ int64_t combination2Id = combination2.id();
+ *config.add_predicate() = combination2;
+
+ // Will be removed.
+ Predicate combination3;
+ combination3.set_id(StringToId("COMBINATION3"));
+ combination3.mutable_combination()->set_operation(LogicalOperation::NOT);
+ combination3.mutable_combination()->add_predicate(simple2Id);
+ int64_t combination3Id = combination3.id();
+ *config.add_predicate() = combination3;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Mark marcher 5 as replaced. Causes simple3, and therefore combination2 to be replaced.
+ set<int64_t> replacedMatchers;
+ replacedMatchers.insert(matcher6Id);
+
+ // Change the condition of simple1 to true.
+ ASSERT_EQ(oldConditionTrackers[0]->getConditionId(), simple1Id);
+ LogEvent event(/*uid=*/0, /*pid=*/0); // Empty event is fine since there are no dimensions.
+ // Mark the stop matcher as matched, condition should be false.
+ vector<MatchingState> eventMatcherValues(6, MatchingState::kNotMatched);
+ eventMatcherValues[1] = MatchingState::kMatched;
+ vector<ConditionState> tmpConditionCache(6, ConditionState::kNotEvaluated);
+ vector<bool> conditionChangeCache(6, false);
+ oldConditionTrackers[0]->evaluateCondition(event, eventMatcherValues, oldConditionTrackers,
+ tmpConditionCache, conditionChangeCache);
+ EXPECT_EQ(tmpConditionCache[0], ConditionState::kFalse);
+ EXPECT_EQ(conditionChangeCache[0], true);
+
+ // New combination matcher. Should have an initial condition of true since it is NOT(simple1).
+ Predicate combination4;
+ combination4.set_id(StringToId("COMBINATION4"));
+ combination4.mutable_combination()->set_operation(LogicalOperation::NOT);
+ combination4.mutable_combination()->add_predicate(simple1Id);
+ int64_t combination4Id = combination4.id();
+ *config.add_predicate() = combination4;
+
+ // Map the matchers in reverse order to force the indices to change.
+ std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
+ const int matcher6Index = 0;
+ newAtomMatchingTrackerMap[matcher6Id] = 0;
+ const int matcher5Index = 1;
+ newAtomMatchingTrackerMap[matcher5Id] = 1;
+ const int matcher4Index = 2;
+ newAtomMatchingTrackerMap[matcher4Id] = 2;
+ const int matcher3Index = 3;
+ newAtomMatchingTrackerMap[matcher3Id] = 3;
+ const int matcher2Index = 4;
+ newAtomMatchingTrackerMap[matcher2Id] = 4;
+ const int matcher1Index = 5;
+ newAtomMatchingTrackerMap[matcher1Id] = 5;
+
+ StatsdConfig newConfig;
+ *newConfig.add_predicate() = simple3;
+ const int simple3Index = 0;
+ *newConfig.add_predicate() = combination2;
+ const int combination2Index = 1;
+ *newConfig.add_predicate() = combination4;
+ const int combination4Index = 2;
+ *newConfig.add_predicate() = simple2;
+ const int simple2Index = 3;
+ *newConfig.add_predicate() = combination1;
+ const int combination1Index = 4;
+ *newConfig.add_predicate() = simple1;
+ const int simple1Index = 5;
+
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ vector<sp<ConditionTracker>> newConditionTrackers;
+ unordered_map<int, vector<int>> trackerToConditionMap;
+ std::vector<ConditionState> conditionCache;
+ std::set<int64_t> replacedConditions;
+ EXPECT_TRUE(updateConditions(key, newConfig, newAtomMatchingTrackerMap, replacedMatchers,
+ oldConditionTrackerMap, oldConditionTrackers,
+ newConditionTrackerMap, newConditionTrackers,
+ trackerToConditionMap, conditionCache, replacedConditions));
+
+ unordered_map<int64_t, int> expectedConditionTrackerMap = {
+ {simple1Id, simple1Index}, {simple2Id, simple2Index},
+ {simple3Id, simple3Index}, {combination1Id, combination1Index},
+ {combination2Id, combination2Index}, {combination4Id, combination4Index},
+ };
+ EXPECT_THAT(newConditionTrackerMap, ContainerEq(expectedConditionTrackerMap));
+
+ ASSERT_EQ(newConditionTrackers.size(), 6);
+ // Make sure all conditions are initialized:
+ for (const sp<ConditionTracker>& tracker : newConditionTrackers) {
+ EXPECT_TRUE(tracker->mInitialized);
+ }
+
+ // Make sure preserved conditions are the same.
+ EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple1Id)],
+ newConditionTrackers[newConditionTrackerMap.at(simple1Id)]);
+ EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple2Id)],
+ newConditionTrackers[newConditionTrackerMap.at(simple2Id)]);
+ EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(combination1Id)],
+ newConditionTrackers[newConditionTrackerMap.at(combination1Id)]);
+
+ // Make sure replaced conditions are different and included in replacedConditions.
+ EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(simple3Id)],
+ newConditionTrackers[newConditionTrackerMap.at(simple3Id)]);
+ EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(combination2Id)],
+ newConditionTrackers[newConditionTrackerMap.at(combination2Id)]);
+ EXPECT_THAT(replacedConditions, ContainerEq(set({simple3Id, combination2Id})));
+
+ // Verify the trackerToConditionMap
+ ASSERT_EQ(trackerToConditionMap.size(), 6);
+ const vector<int>& matcher1Conditions = trackerToConditionMap[matcher1Index];
+ EXPECT_THAT(matcher1Conditions, UnorderedElementsAre(simple1Index, combination1Index,
+ combination2Index, combination4Index));
+ const vector<int>& matcher2Conditions = trackerToConditionMap[matcher2Index];
+ EXPECT_THAT(matcher2Conditions, UnorderedElementsAre(simple1Index, combination1Index,
+ combination2Index, combination4Index));
+ const vector<int>& matcher3Conditions = trackerToConditionMap[matcher3Index];
+ EXPECT_THAT(matcher3Conditions, UnorderedElementsAre(simple2Index, combination1Index));
+ const vector<int>& matcher4Conditions = trackerToConditionMap[matcher4Index];
+ EXPECT_THAT(matcher4Conditions, UnorderedElementsAre(simple2Index, combination1Index));
+ const vector<int>& matcher5Conditions = trackerToConditionMap[matcher5Index];
+ EXPECT_THAT(matcher5Conditions, UnorderedElementsAre(simple3Index, combination2Index));
+ const vector<int>& matcher6Conditions = trackerToConditionMap[matcher6Index];
+ EXPECT_THAT(matcher6Conditions, UnorderedElementsAre(simple3Index, combination2Index));
+
+ // Verify the conditionCache. Specifically, simple1 is false and combination4 is true.
+ ASSERT_EQ(conditionCache.size(), 6);
+ EXPECT_EQ(conditionCache[simple1Index], ConditionState::kFalse);
+ EXPECT_EQ(conditionCache[simple2Index], ConditionState::kUnknown);
+ EXPECT_EQ(conditionCache[simple3Index], ConditionState::kUnknown);
+ EXPECT_EQ(conditionCache[combination1Index], ConditionState::kUnknown);
+ EXPECT_EQ(conditionCache[combination2Index], ConditionState::kUnknown);
+ EXPECT_EQ(conditionCache[combination4Index], ConditionState::kTrue);
+
+ // Verify tracker indices/ids are correct.
+ EXPECT_EQ(newConditionTrackers[simple1Index]->getConditionId(), simple1Id);
+ EXPECT_EQ(newConditionTrackers[simple1Index]->mIndex, simple1Index);
+ EXPECT_TRUE(newConditionTrackers[simple1Index]->IsSimpleCondition());
+ EXPECT_EQ(newConditionTrackers[simple2Index]->getConditionId(), simple2Id);
+ EXPECT_EQ(newConditionTrackers[simple2Index]->mIndex, simple2Index);
+ EXPECT_TRUE(newConditionTrackers[simple2Index]->IsSimpleCondition());
+ EXPECT_EQ(newConditionTrackers[simple3Index]->getConditionId(), simple3Id);
+ EXPECT_EQ(newConditionTrackers[simple3Index]->mIndex, simple3Index);
+ EXPECT_TRUE(newConditionTrackers[simple3Index]->IsSimpleCondition());
+ EXPECT_EQ(newConditionTrackers[combination1Index]->getConditionId(), combination1Id);
+ EXPECT_EQ(newConditionTrackers[combination1Index]->mIndex, combination1Index);
+ EXPECT_FALSE(newConditionTrackers[combination1Index]->IsSimpleCondition());
+ EXPECT_EQ(newConditionTrackers[combination2Index]->getConditionId(), combination2Id);
+ EXPECT_EQ(newConditionTrackers[combination2Index]->mIndex, combination2Index);
+ EXPECT_FALSE(newConditionTrackers[combination2Index]->IsSimpleCondition());
+ EXPECT_EQ(newConditionTrackers[combination4Index]->getConditionId(), combination4Id);
+ EXPECT_EQ(newConditionTrackers[combination4Index]->mIndex, combination4Index);
+ EXPECT_FALSE(newConditionTrackers[combination4Index]->IsSimpleCondition());
+
+ // Verify preserved trackers have indices updated.
+ SimpleConditionTracker* simpleTracker1 =
+ static_cast<SimpleConditionTracker*>(newConditionTrackers[simple1Index].get());
+ EXPECT_EQ(simpleTracker1->mStartLogMatcherIndex, matcher1Index);
+ EXPECT_EQ(simpleTracker1->mStopLogMatcherIndex, matcher2Index);
+ EXPECT_EQ(simpleTracker1->mStopAllLogMatcherIndex, -1);
+
+ SimpleConditionTracker* simpleTracker2 =
+ static_cast<SimpleConditionTracker*>(newConditionTrackers[simple2Index].get());
+ EXPECT_EQ(simpleTracker2->mStartLogMatcherIndex, matcher3Index);
+ EXPECT_EQ(simpleTracker2->mStopLogMatcherIndex, matcher4Index);
+ EXPECT_EQ(simpleTracker2->mStopAllLogMatcherIndex, -1);
+
+ CombinationConditionTracker* combinationTracker1 = static_cast<CombinationConditionTracker*>(
+ newConditionTrackers[combination1Index].get());
+ EXPECT_THAT(combinationTracker1->mChildren, UnorderedElementsAre(simple1Index, simple2Index));
+ EXPECT_THAT(combinationTracker1->mUnSlicedChildren,
+ UnorderedElementsAre(simple1Index, simple2Index));
+ EXPECT_THAT(combinationTracker1->mSlicedChildren, IsEmpty());
+}
} // namespace statsd
} // namespace os
} // namespace android
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
index d6db4c1..e6583c9 100644
--- a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
+++ b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
@@ -384,8 +384,9 @@
StatsdConfig config = buildConfigWithDifferentPredicates();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -400,9 +401,9 @@
EXPECT_TRUE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
ASSERT_EQ(4u, allMetricProducers.size());
@@ -433,8 +434,9 @@
StatsdConfig config = buildGoodConfig();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -449,9 +451,9 @@
EXPECT_TRUE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
ASSERT_EQ(1u, allMetricProducers.size());
@@ -470,8 +472,9 @@
StatsdConfig config = buildDimensionMetricsWithMultiTags();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -486,9 +489,9 @@
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -501,8 +504,9 @@
StatsdConfig config = buildCircleMatchers();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -517,9 +521,9 @@
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -532,8 +536,9 @@
StatsdConfig config = buildMissingMatchers();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -547,9 +552,9 @@
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -562,8 +567,9 @@
StatsdConfig config = buildMissingPredicate();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -577,9 +583,9 @@
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -592,8 +598,9 @@
StatsdConfig config = buildCirclePredicates();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -608,9 +615,9 @@
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -623,8 +630,9 @@
StatsdConfig config = buildAlertWithUnknownMetric();
set<int> allTagIds;
vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
- unordered_map<int64_t, int> logTrackerMap;
+ unordered_map<int64_t, int> atomMatchingTrackerMap;
vector<sp<ConditionTracker>> allConditionTrackers;
+ unordered_map<int64_t, int> conditionTrackerMap;
vector<sp<MetricProducer>> allMetricProducers;
std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
std::vector<sp<AlarmTracker>> allAlarmTrackers;
@@ -639,9 +647,9 @@
EXPECT_FALSE(initStatsdConfig(
kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, logTrackerMap,
- allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
- conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
+ allConditionTrackers, conditionTrackerMap, allMetricProducers, allAnomalyTrackers,
+ allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
metricsWithActivation, noReportMetricIds));
}
@@ -649,6 +657,7 @@
TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerInvalidMatcher) {
sp<UidMap> uidMap = new UidMap();
AtomMatcher matcher;
+ // Matcher has no contents_case (simple/combination), so it is invalid.
matcher.set_id(21);
EXPECT_EQ(createAtomMatchingTracker(matcher, 0, uidMap), nullptr);
}
@@ -699,6 +708,65 @@
ASSERT_EQ(atomIds.size(), 0);
}
+TEST(MetricsManagerTest, TestCreateConditionTrackerInvalid) {
+ const ConfigKey key(123, 456);
+ // Predicate has no contents_case (simple/combination), so it is invalid.
+ Predicate predicate;
+ predicate.set_id(21);
+ unordered_map<int64_t, int> atomTrackerMap;
+ EXPECT_EQ(createConditionTracker(key, predicate, 0, atomTrackerMap), nullptr);
+}
+
+TEST(MetricsManagerTest, TestCreateConditionTrackerSimple) {
+ int index = 1;
+ int64_t id = 987;
+ const ConfigKey key(123, 456);
+
+ int startMatcherIndex = 2, stopMatcherIndex = 0, stopAllMatcherIndex = 1;
+ int64_t startMatcherId = 246, stopMatcherId = 153, stopAllMatcherId = 975;
+
+ Predicate predicate;
+ predicate.set_id(id);
+ SimplePredicate* simplePredicate = predicate.mutable_simple_predicate();
+ simplePredicate->set_start(startMatcherId);
+ simplePredicate->set_stop(stopMatcherId);
+ simplePredicate->set_stop_all(stopAllMatcherId);
+
+ unordered_map<int64_t, int> atomTrackerMap;
+ atomTrackerMap[startMatcherId] = startMatcherIndex;
+ atomTrackerMap[stopMatcherId] = stopMatcherIndex;
+ atomTrackerMap[stopAllMatcherId] = stopAllMatcherIndex;
+
+ sp<ConditionTracker> tracker = createConditionTracker(key, predicate, index, atomTrackerMap);
+ EXPECT_EQ(tracker->getConditionId(), id);
+ EXPECT_EQ(tracker->isSliced(), false);
+ EXPECT_TRUE(tracker->IsSimpleCondition());
+ const set<int>& interestedMatchers = tracker->getAtomMatchingTrackerIndex();
+ ASSERT_EQ(interestedMatchers.size(), 3);
+ ASSERT_EQ(interestedMatchers.count(startMatcherIndex), 1);
+ ASSERT_EQ(interestedMatchers.count(stopMatcherIndex), 1);
+ ASSERT_EQ(interestedMatchers.count(stopAllMatcherIndex), 1);
+}
+
+TEST(MetricsManagerTest, TestCreateConditionTrackerCombination) {
+ int index = 1;
+ int64_t id = 987;
+ const ConfigKey key(123, 456);
+
+ Predicate predicate;
+ predicate.set_id(id);
+ Predicate_Combination* combinationPredicate = predicate.mutable_combination();
+ combinationPredicate->set_operation(LogicalOperation::AND);
+ combinationPredicate->add_predicate(888);
+ combinationPredicate->add_predicate(777);
+
+ // Combination conditions must be initialized to set most state.
+ unordered_map<int64_t, int> atomTrackerMap;
+ sp<ConditionTracker> tracker = createConditionTracker(key, predicate, index, atomTrackerMap);
+ EXPECT_EQ(tracker->getConditionId(), id);
+ EXPECT_FALSE(tracker->IsSimpleCondition());
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 0055711..7087b60 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1160,9 +1160,17 @@
// TODO: Add as AppProtoEnums
public static final int OP_PHONE_CALL_CAMERA = 101;
+ /**
+ * Audio is being recorded for hotword detection.
+ *
+ * @hide
+ */
+ // TODO: Add as AppProtoEnums
+ public static final int OP_RECORD_AUDIO_HOTWORD = 102;
+
/** @hide */
@UnsupportedAppUsage
- public static final int _NUM_OP = 102;
+ public static final int _NUM_OP = 103;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1497,6 +1505,13 @@
*/
public static final String OPSTR_PHONE_CALL_CAMERA = "android:phone_call_camera";
+ /**
+ * Audio is being recorded for hotword detection.
+ *
+ * @hide
+ */
+ public static final String OPSTR_RECORD_AUDIO_HOTWORD = "android:record_audio_hotword";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1688,6 +1703,7 @@
OP_NO_ISOLATED_STORAGE, // NO_ISOLATED_STORAGE
OP_PHONE_CALL_MICROPHONE, // OP_PHONE_CALL_MICROPHONE
OP_PHONE_CALL_CAMERA, // OP_PHONE_CALL_CAMERA
+ OP_RECORD_AUDIO_HOTWORD, // RECORD_AUDIO_HOTWORD
};
/**
@@ -1796,6 +1812,7 @@
OPSTR_NO_ISOLATED_STORAGE,
OPSTR_PHONE_CALL_MICROPHONE,
OPSTR_PHONE_CALL_CAMERA,
+ OPSTR_RECORD_AUDIO_HOTWORD,
};
/**
@@ -1905,6 +1922,7 @@
"NO_ISOLATED_STORAGE",
"PHONE_CALL_MICROPHONE",
"PHONE_CALL_CAMERA",
+ "RECORD_AUDIO_HOTWORD",
};
/**
@@ -2015,6 +2033,7 @@
null, // no permission for OP_NO_ISOLATED_STORAGE
null, // no permission for OP_PHONE_CALL_MICROPHONE
null, // no permission for OP_PHONE_CALL_CAMERA
+ null, // no permission for OP_RECORD_AUDIO_HOTWORD
};
/**
@@ -2125,6 +2144,7 @@
null, // NO_ISOLATED_STORAGE
null, // PHONE_CALL_MICROPHONE
null, // PHONE_CALL_MICROPHONE
+ null, // RECORD_AUDIO_HOTWORD
};
/**
@@ -2234,6 +2254,7 @@
null, // NO_ISOLATED_STORAGE
null, // PHONE_CALL_MICROPHONE
null, // PHONE_CALL_CAMERA
+ null, // RECORD_AUDIO_HOTWORD
};
/**
@@ -2342,6 +2363,7 @@
AppOpsManager.MODE_ERRORED, // OP_NO_ISOLATED_STORAGE
AppOpsManager.MODE_ALLOWED, // PHONE_CALL_MICROPHONE
AppOpsManager.MODE_ALLOWED, // PHONE_CALL_CAMERA
+ AppOpsManager.MODE_ALLOWED, // OP_RECORD_AUDIO_HOTWORD
};
/**
@@ -2454,6 +2476,7 @@
true, // NO_ISOLATED_STORAGE
false, // PHONE_CALL_MICROPHONE
false, // PHONE_CALL_CAMERA
+ false, // RECORD_AUDIO_HOTWORD
};
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 340d5a1..2780036 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -73,6 +73,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelableException;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
@@ -107,7 +108,11 @@
import libcore.util.EmptyArray;
+import java.io.IOException;
import java.lang.ref.WeakReference;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -135,6 +140,12 @@
// Default flags to use with PackageManager when no flags are given.
private static final int sDefaultFlags = GET_SHARED_LIBRARY_FILES;
+ /** Default set of checksums - includes all available checksums.
+ * @see PackageManager#getChecksums */
+ private static final int DEFAULT_CHECKSUMS =
+ WHOLE_MERKLE_ROOT_4K_SHA256 | WHOLE_MD5 | WHOLE_SHA1 | WHOLE_SHA256 | WHOLE_SHA512
+ | PARTIAL_MERKLE_ROOT_1M_SHA256 | PARTIAL_MERKLE_ROOT_1M_SHA512;
+
// Name of the resource which provides background permission button string
public static final String APP_PERMISSION_BUTTON_ALLOW_ALWAYS =
"app_permission_button_allow_always";
@@ -945,6 +956,39 @@
}
}
+ private static List<byte[]> encodeCertificates(List<Certificate> certs) throws
+ CertificateEncodingException {
+ if (certs == null) {
+ return null;
+ }
+ List<byte[]> result = new ArrayList<>(certs.size());
+ for (Certificate cert : certs) {
+ if (!(cert instanceof X509Certificate)) {
+ throw new CertificateEncodingException("Only X509 certificates supported.");
+ }
+ result.add(cert.getEncoded());
+ }
+ return result;
+ }
+
+ @Override
+ public void getChecksums(@NonNull String packageName, boolean includeSplits,
+ @FileChecksumKind int required, @Nullable List<Certificate> trustedInstallers,
+ @NonNull IntentSender statusReceiver)
+ throws CertificateEncodingException, IOException, NameNotFoundException {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(statusReceiver);
+ try {
+ mPM.getChecksums(packageName, includeSplits, DEFAULT_CHECKSUMS, required,
+ encodeCertificates(trustedInstallers), statusReceiver, getUserId());
+ } catch (ParcelableException e) {
+ e.maybeRethrow(PackageManager.NameNotFoundException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Wrap the cached value in a class that does deep compares on string
* arrays. The comparison is needed only for the verification mode of
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 7cd3fca..9e4ab33 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -54,6 +54,7 @@
import java.io.PrintWriter;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
@@ -245,7 +246,7 @@
/**
* A cache of DisplayId, DisplayAdjustments to Display.
*/
- private final ArrayMap<Pair<Integer, DisplayAdjustments>, WeakReference<Display>>
+ private final ArrayMap<Pair<Integer, DisplayAdjustments>, SoftReference<Display>>
mAdjustedDisplays = new ArrayMap<>();
/**
@@ -373,25 +374,28 @@
? new DisplayAdjustments(displayAdjustments) : new DisplayAdjustments();
final Pair<Integer, DisplayAdjustments> key =
Pair.create(displayId, displayAdjustmentsCopy);
+ SoftReference<Display> sd;
synchronized (this) {
- WeakReference<Display> wd = mAdjustedDisplays.get(key);
- if (wd != null) {
- final Display display = wd.get();
- if (display != null) {
- return display;
- }
- }
- final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
- if (dm == null) {
- // may be null early in system startup
- return null;
- }
- final Display display = dm.getCompatibleDisplay(displayId, key.second);
- if (display != null) {
- mAdjustedDisplays.put(key, new WeakReference<>(display));
- }
- return display;
+ sd = mAdjustedDisplays.get(key);
}
+ if (sd != null) {
+ final Display display = sd.get();
+ if (display != null) {
+ return display;
+ }
+ }
+ final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
+ if (dm == null) {
+ // may be null early in system startup
+ return null;
+ }
+ final Display display = dm.getCompatibleDisplay(displayId, key.second);
+ if (display != null) {
+ synchronized (this) {
+ mAdjustedDisplays.put(key, new SoftReference<>(display));
+ }
+ }
+ return display;
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c61426d..98de85d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9751,21 +9751,6 @@
}
/**
- * @hide
- * Return if this user is a system-only user. An admin can manage a device from a system only
- * user by calling {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE}.
- * @param admin Which device owner this request is associated with.
- * @return if this user is a system-only user.
- */
- public boolean isSystemOnlyUser(@NonNull ComponentName admin) {
- try {
- return mService.isSystemOnlyUser(admin);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- }
-
- /**
* Called by device owner, or profile owner on organization-owned device, to get the MAC
* address of the Wi-Fi device.
*
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 9c6a274..1c7b617 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -345,7 +345,6 @@
void setKeepUninstalledPackages(in ComponentName admin, in String callerPackage, in List<String> packageList);
List<String> getKeepUninstalledPackages(in ComponentName admin, in String callerPackage);
boolean isManagedProfile(in ComponentName admin);
- boolean isSystemOnlyUser(in ComponentName admin);
String getWifiMacAddress(in ComponentName admin);
void reboot(in ComponentName admin);
diff --git a/core/java/android/app/timezonedetector/TEST_MAPPING b/core/java/android/app/timezonedetector/TEST_MAPPING
new file mode 100644
index 0000000..46f2319
--- /dev/null
+++ b/core/java/android/app/timezonedetector/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.app.timezonedetector."
+ }
+ ]
+ }
+ ]
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt b/core/java/android/content/pm/FileChecksum.aidl
similarity index 76%
copy from packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt
copy to core/java/android/content/pm/FileChecksum.aidl
index 9d05843..109f211 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt
+++ b/core/java/android/content/pm/FileChecksum.aidl
@@ -14,11 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.settings
+package android.content.pm;
-import android.content.ContentResolver
+parcelable FileChecksum;
-interface CurrentUserContentResolverProvider {
-
- val currentUserContentResolver: ContentResolver
-}
\ No newline at end of file
diff --git a/core/java/android/content/pm/FileChecksum.java b/core/java/android/content/pm/FileChecksum.java
new file mode 100644
index 0000000..55430c2
--- /dev/null
+++ b/core/java/android/content/pm/FileChecksum.java
@@ -0,0 +1,238 @@
+/*
+ * 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 android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.IntentSender;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+/**
+ * A typed checksum.
+ *
+ * @see PackageManager#getChecksums(String, boolean, int, List, IntentSender)
+ */
+@DataClass(genHiddenConstructor = true)
+public final class FileChecksum implements Parcelable {
+ /**
+ * Checksum for which split. Null indicates base.apk.
+ */
+ private final @Nullable String mSplitName;
+ /**
+ * Checksum kind.
+ */
+ private final @PackageManager.FileChecksumKind int mKind;
+ /**
+ * Checksum value.
+ */
+ private final @NonNull byte[] mValue;
+ /**
+ * For Installer-provided checksums, certificate of the Installer/AppStore.
+ */
+ private final @Nullable byte[] mSourceCertificate;
+
+ /**
+ * Constructor, internal use only
+ *
+ * @hide
+ */
+ public FileChecksum(@Nullable String splitName, @PackageManager.FileChecksumKind int kind,
+ @NonNull byte[] value) {
+ this(splitName, kind, value, (byte[]) null);
+ }
+
+ /**
+ * Constructor, internal use only
+ *
+ * @hide
+ */
+ public FileChecksum(@Nullable String splitName, @PackageManager.FileChecksumKind int kind,
+ @NonNull byte[] value, @Nullable Certificate sourceCertificate)
+ throws CertificateEncodingException {
+ this(splitName, kind, value,
+ (sourceCertificate != null) ? sourceCertificate.getEncoded() : null);
+ }
+
+ /**
+ * Certificate of the source of this checksum.
+ * @throws CertificateException in case when certificate can't be re-created from serialized
+ * data.
+ */
+ public @Nullable Certificate getSourceCertificate() throws CertificateException {
+ if (mSourceCertificate == null) {
+ return null;
+ }
+ final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ final InputStream is = new ByteArrayInputStream(mSourceCertificate);
+ final X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
+ return cert;
+ }
+
+
+
+ // Code below generated by codegen v1.0.15.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/FileChecksum.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new FileChecksum.
+ *
+ * @param splitName
+ * Checksum for which split. Null indicates base.apk.
+ * @param kind
+ * Checksum kind.
+ * @param value
+ * Checksum value.
+ * @param sourceCertificate
+ * For Installer-provided checksums, certificate of the Installer/AppStore.
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public FileChecksum(
+ @Nullable String splitName,
+ @PackageManager.FileChecksumKind int kind,
+ @NonNull byte[] value,
+ @Nullable byte[] sourceCertificate) {
+ this.mSplitName = splitName;
+ this.mKind = kind;
+ com.android.internal.util.AnnotationValidations.validate(
+ PackageManager.FileChecksumKind.class, null, mKind);
+ this.mValue = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mValue);
+ this.mSourceCertificate = sourceCertificate;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * Checksum for which split. Null indicates base.apk.
+ */
+ @DataClass.Generated.Member
+ public @Nullable String getSplitName() {
+ return mSplitName;
+ }
+
+ /**
+ * Checksum kind.
+ */
+ @DataClass.Generated.Member
+ public @PackageManager.FileChecksumKind int getKind() {
+ return mKind;
+ }
+
+ /**
+ * Checksum value.
+ */
+ @DataClass.Generated.Member
+ public @NonNull byte[] getValue() {
+ return mValue;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ byte flg = 0;
+ if (mSplitName != null) flg |= 0x1;
+ if (mSourceCertificate != null) flg |= 0x8;
+ dest.writeByte(flg);
+ if (mSplitName != null) dest.writeString(mSplitName);
+ dest.writeInt(mKind);
+ dest.writeByteArray(mValue);
+ if (mSourceCertificate != null) dest.writeByteArray(mSourceCertificate);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ FileChecksum(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ byte flg = in.readByte();
+ String splitName = (flg & 0x1) == 0 ? null : in.readString();
+ int kind = in.readInt();
+ byte[] value = in.createByteArray();
+ byte[] sourceCertificate = (flg & 0x8) == 0 ? null : in.createByteArray();
+
+ this.mSplitName = splitName;
+ this.mKind = kind;
+ com.android.internal.util.AnnotationValidations.validate(
+ PackageManager.FileChecksumKind.class, null, mKind);
+ this.mValue = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mValue);
+ this.mSourceCertificate = sourceCertificate;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<FileChecksum> CREATOR
+ = new Parcelable.Creator<FileChecksum>() {
+ @Override
+ public FileChecksum[] newArray(int size) {
+ return new FileChecksum[size];
+ }
+
+ @Override
+ public FileChecksum createFromParcel(@NonNull Parcel in) {
+ return new FileChecksum(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1598322801861L,
+ codegenVersion = "1.0.15",
+ sourceFile = "frameworks/base/core/java/android/content/pm/FileChecksum.java",
+ inputSignatures = "private final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.content.pm.PackageManager.FileChecksumKind int mKind\nprivate final @android.annotation.NonNull byte[] mValue\nprivate final @android.annotation.Nullable byte[] mSourceCertificate\npublic @android.annotation.Nullable java.security.cert.Certificate getSourceCertificate()\nclass FileChecksum extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 6a8dd81..1f8cee2 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -743,6 +743,8 @@
void notifyPackagesReplacedReceived(in String[] packages);
+ void getChecksums(in String packageName, boolean includeSplits, int optional, int required, in List trustedInstallers, in IntentSender statusReceiver, int userId);
+
//------------------------------------------------------------------------
//
// The following binder interfaces have been moved to IPermissionManager
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7b2955d..da8d15a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -79,8 +79,11 @@
import dalvik.system.VMRuntime;
import java.io.File;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -3305,6 +3308,13 @@
public static final String EXTRA_FAILURE_EXISTING_PERMISSION
= "android.content.pm.extra.FAILURE_EXISTING_PERMISSION";
+ /**
+ * Extra field name for the ID of a package pending verification. Passed to
+ * a package verifier and is used to call back to
+ * @see #getChecksums
+ */
+ public static final String EXTRA_CHECKSUMS = "android.content.pm.extra.CHECKSUMS";
+
/**
* Permission flag: The permission is set in its current state
* by the user and apps can still request it at runtime.
@@ -7842,6 +7852,114 @@
}
/**
+ * Root SHA256 hash of a 4K Merkle tree computed over all file bytes.
+ * <a href="https://source.android.com/security/apksigning/v4">See APK Signature Scheme V4</a>.
+ * <a href="https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/tree/Documentation/filesystems/fsverity.rst">See fs-verity</a>.
+ *
+ * @see #getChecksums
+ */
+ public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 0x00000001;
+
+ /**
+ * MD5 hash computed over all file bytes.
+ *
+ * @see #getChecksums
+ */
+ public static final int WHOLE_MD5 = 0x00000002;
+
+ /**
+ * SHA1 hash computed over all file bytes.
+ *
+ * @see #getChecksums
+ */
+ public static final int WHOLE_SHA1 = 0x00000004;
+
+ /**
+ * SHA256 hash computed over all file bytes.
+ *
+ * @see #getChecksums
+ */
+ public static final int WHOLE_SHA256 = 0x00000008;
+
+ /**
+ * SHA512 hash computed over all file bytes.
+ *
+ * @see #getChecksums
+ */
+ public static final int WHOLE_SHA512 = 0x00000010;
+
+ /**
+ * Root SHA256 hash of a 1M Merkle tree computed over protected content.
+ * Excludes signing block.
+ * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>.
+ *
+ * @see #getChecksums
+ */
+ public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 0x00000020;
+
+ /**
+ * Root SHA512 hash of a 1M Merkle tree computed over protected content.
+ * Excludes signing block.
+ * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>.
+ *
+ * @see #getChecksums
+ */
+ public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 0x00000040;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = {"WHOLE_", "PARTIAL_"}, value = {
+ WHOLE_MERKLE_ROOT_4K_SHA256,
+ WHOLE_MD5,
+ WHOLE_SHA1,
+ WHOLE_SHA256,
+ WHOLE_SHA512,
+ PARTIAL_MERKLE_ROOT_1M_SHA256,
+ PARTIAL_MERKLE_ROOT_1M_SHA512,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FileChecksumKind {}
+
+ /**
+ * Trust any Installer to provide checksums for the package.
+ * @see #getChecksums
+ */
+ public static final @Nullable List<Certificate> TRUST_ALL = null;
+
+ /**
+ * Don't trust any Installer to provide checksums for the package.
+ * This effectively disables optimized Installer-enforced checksums.
+ * @see #getChecksums
+ */
+ public static final @NonNull List<Certificate> TRUST_NONE = Collections.emptyList();
+
+ /**
+ * Returns the checksums for APKs within a package.
+ *
+ * By default returns all readily available checksums:
+ * - enforced by platform,
+ * - enforced by installer.
+ * If caller needs a specific checksum kind, they can specify it as required.
+ *
+ * @param packageName whose checksums to return.
+ * @param includeSplits whether to include checksums for non-base splits.
+ * @param required explicitly request the checksum kinds. Will incur significant
+ * CPU/memory/disk usage.
+ * @param trustedInstallers for checksums enforced by Installer, which ones to be trusted.
+ * {@link #TRUST_ALL} will return checksums from any Installer,
+ * {@link #TRUST_NONE} disables optimized Installer-enforced checksums.
+ * @param statusReceiver called once when the results are available as
+ * {@link #EXTRA_CHECKSUMS} of type FileChecksum[].
+ * @throws CertificateEncodingException if an encoding error occurs for trustedInstallers.
+ * @throws NameNotFoundException if a package with the given name cannot be found on the system.
+ */
+ public void getChecksums(@NonNull String packageName, boolean includeSplits,
+ @FileChecksumKind int required, @Nullable List<Certificate> trustedInstallers,
+ @NonNull IntentSender statusReceiver)
+ throws CertificateEncodingException, IOException, NameNotFoundException {
+ throw new UnsupportedOperationException("getChecksums not implemented in subclass");
+ }
+
+ /**
* @return the default text classifier package name, or null if there's none.
*
* @hide
diff --git a/core/java/android/inputmethodservice/TEST_MAPPING b/core/java/android/inputmethodservice/TEST_MAPPING
new file mode 100644
index 0000000..0ccd75d
--- /dev/null
+++ b/core/java/android/inputmethodservice/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/core/java/android/view/inputmethod"
+ }
+ ]
+}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 2465b0e..81a147c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -43,7 +43,6 @@
import android.content.IntentSender;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo.UserInfoFlag;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -3174,28 +3173,55 @@
}
/**
- * Returns information for all users on this device, including ones marked for deletion.
- * To retrieve only users that are alive, use {@link #getUsers(boolean)}.
+ * Returns information for all fully-created users on this device, including ones marked for
+ * deletion.
*
- * @return the list of users that exist on the device.
+ * <p>To retrieve only users that are not marked for deletion, use {@link #getAliveUsers()}.
+ *
+ * <p>To retrieve *all* users (including partial and pre-created users), use
+ * {@link #getUsers(boolean, boolean, boolean)) getUsers(false, false, false)}.
+ *
+ * <p>To retrieve a more specific list of users, use
+ * {@link #getUsers(boolean, boolean, boolean)}.
+ *
+ * @return the list of users that were created.
+ *
* @hide
*/
@UnsupportedAppUsage
@RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public List<UserInfo> getUsers() {
- return getUsers(/* excludeDying= */ false);
+ return getUsers(/*excludePartial= */ true, /* excludeDying= */ false,
+ /* excludePreCreated= */ true);
}
/**
- * Returns information for all users on this device. Requires
- * {@link android.Manifest.permission#MANAGE_USERS} permission.
+ * Returns information for all "usable" users on this device (i.e, it excludes users that are
+ * marked for deletion, pre-created users, etc...).
*
- * @param excludeDying specify if the list should exclude users being
- * removed.
+ * <p>To retrieve all fully-created users, use {@link #getUsers()}.
+ *
+ * <p>To retrieve a more specific list of users, use
+ * {@link #getUsers(boolean, boolean, boolean)}.
+ *
* @return the list of users that were created.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public @NonNull List<UserInfo> getAliveUsers() {
+ return getUsers(/*excludePartial= */ true, /* excludeDying= */ true,
+ /* excludePreCreated= */ true);
+ }
+
+ /**
+ * @deprecated use {@link #getAliveUsers()} for {@code getUsers(true)}, or
+ * {@link #getUsers()} for @code getUsers(false)}.
+ *
+ * @hide
+ */
+ @Deprecated
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
return getUsers(/*excludePartial= */ true, excludeDying,
/* excludePreCreated= */ true);
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 327bca2..d55fc51 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -218,8 +218,15 @@
}
/** {@hide} */
- private void enforceTree(Uri documentUri) {
- if (isTreeUri(documentUri)) {
+ private void enforceTreeForExtraUris(Bundle extras) {
+ enforceTree(extras.getParcelable(DocumentsContract.EXTRA_URI));
+ enforceTree(extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI));
+ enforceTree(extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI));
+ }
+
+ /** {@hide} */
+ private void enforceTree(@Nullable Uri documentUri) {
+ if (documentUri != null && isTreeUri(documentUri)) {
final String parent = getTreeDocumentId(documentUri);
final String child = getDocumentId(documentUri);
if (Objects.equals(parent, child)) {
@@ -1076,6 +1083,9 @@
final Context context = getContext();
final Bundle out = new Bundle();
+ // If the URI is a tree URI performs some validation.
+ enforceTreeForExtraUris(extras);
+
if (METHOD_EJECT_ROOT.equals(method)) {
// Given that certain system apps can hold MOUNT_UNMOUNT permission, but only apps
// signed with platform signature can hold MANAGE_DOCUMENTS, we are going to check for
@@ -1099,9 +1109,6 @@
"Requested authority " + authority + " doesn't match provider " + mAuthority);
}
- // If the URI is a tree URI performs some validation.
- enforceTree(documentUri);
-
if (METHOD_IS_CHILD_DOCUMENT.equals(method)) {
enforceReadPermissionInner(documentUri, getCallingPackage(),
getCallingAttributionTag(), null);
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 6e34666..f74990a 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -149,7 +149,7 @@
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v2.
* @throws IOException if an I/O error occurs while reading the APK file.
*/
- private static SignatureInfo findSignature(RandomAccessFile apk)
+ public static SignatureInfo findSignature(RandomAccessFile apk)
throws IOException, SignatureNotFoundException {
return ApkSigningBlockUtils.findSignature(apk, APK_SIGNATURE_SCHEME_V2_BLOCK_ID);
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 9357285..5f963b0 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -142,7 +142,7 @@
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
* @throws IOException if an I/O error occurs while reading the APK file.
*/
- private static SignatureInfo findSignature(RandomAccessFile apk)
+ public static SignatureInfo findSignature(RandomAccessFile apk)
throws IOException, SignatureNotFoundException {
return ApkSigningBlockUtils.findSignature(apk, APK_SIGNATURE_SCHEME_V3_BLOCK_ID);
}
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index e0258f7..02edb7e 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -92,6 +92,20 @@
private static PackageParser.SigningDetails verifySignatures(String apkPath,
@SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
throws PackageParserException {
+ return verifySignaturesInternal(apkPath, minSignatureSchemeVersion,
+ verifyFull).signingDetails;
+ }
+
+ /**
+ * Verifies the provided APK using all allowed signing schemas.
+ * @return the certificates associated with each signer and content digests.
+ * @param verifyFull whether to verify all contents of this APK or just collect certificates.
+ * @throws PackageParserException if there was a problem collecting certificates
+ * @hide
+ */
+ public static SigningDetailsWithDigests verifySignaturesInternal(String apkPath,
+ @SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
+ throws PackageParserException {
if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V4) {
// V3 and before are older than the requested minimum signing version
@@ -121,7 +135,7 @@
return verifyV3AndBelowSignatures(apkPath, minSignatureSchemeVersion, verifyFull);
}
- private static PackageParser.SigningDetails verifyV3AndBelowSignatures(String apkPath,
+ private static SigningDetailsWithDigests verifyV3AndBelowSignatures(String apkPath,
@SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
throws PackageParserException {
// try v3
@@ -174,7 +188,7 @@
* @throws SignatureNotFoundException if there are no V4 signatures in the APK
* @throws PackageParserException if there was a problem collecting certificates
*/
- private static PackageParser.SigningDetails verifyV4Signature(String apkPath,
+ private static SigningDetailsWithDigests verifyV4Signature(String apkPath,
@SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
throws SignatureNotFoundException, PackageParserException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV4" : "certsOnlyV4");
@@ -234,8 +248,8 @@
}
}
- return new PackageParser.SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V4);
+ return new SigningDetailsWithDigests(new PackageParser.SigningDetails(signerSigs,
+ SignatureSchemeVersion.SIGNING_BLOCK_V4), vSigner.contentDigests);
} catch (SignatureNotFoundException e) {
throw e;
} catch (Exception e) {
@@ -256,8 +270,8 @@
* @throws SignatureNotFoundException if there are no V3 signatures in the APK
* @throws PackageParserException if there was a problem collecting certificates
*/
- private static PackageParser.SigningDetails verifyV3Signature(String apkPath,
- boolean verifyFull) throws SignatureNotFoundException, PackageParserException {
+ private static SigningDetailsWithDigests verifyV3Signature(String apkPath, boolean verifyFull)
+ throws SignatureNotFoundException, PackageParserException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV3" : "certsOnlyV3");
try {
ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
@@ -275,8 +289,9 @@
pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
}
}
- return new PackageParser.SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V3, pastSignerSigs);
+ return new SigningDetailsWithDigests(new PackageParser.SigningDetails(signerSigs,
+ SignatureSchemeVersion.SIGNING_BLOCK_V3, pastSignerSigs),
+ vSigner.contentDigests);
} catch (SignatureNotFoundException e) {
throw e;
} catch (Exception e) {
@@ -297,15 +312,16 @@
* @throws SignatureNotFoundException if there are no V2 signatures in the APK
* @throws PackageParserException if there was a problem collecting certificates
*/
- private static PackageParser.SigningDetails verifyV2Signature(String apkPath,
- boolean verifyFull) throws SignatureNotFoundException, PackageParserException {
+ private static SigningDetailsWithDigests verifyV2Signature(String apkPath, boolean verifyFull)
+ throws SignatureNotFoundException, PackageParserException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV2" : "certsOnlyV2");
try {
- Certificate[][] signerCerts = verifyFull ? ApkSignatureSchemeV2Verifier.verify(apkPath)
- : ApkSignatureSchemeV2Verifier.unsafeGetCertsWithoutVerification(apkPath);
+ ApkSignatureSchemeV2Verifier.VerifiedSigner vSigner =
+ ApkSignatureSchemeV2Verifier.verify(apkPath, verifyFull);
+ Certificate[][] signerCerts = vSigner.certs;
Signature[] signerSigs = convertToSignatures(signerCerts);
- return new PackageParser.SigningDetails(signerSigs,
- SignatureSchemeVersion.SIGNING_BLOCK_V2);
+ return new SigningDetailsWithDigests(new PackageParser.SigningDetails(signerSigs,
+ SignatureSchemeVersion.SIGNING_BLOCK_V2), vSigner.contentDigests);
} catch (SignatureNotFoundException e) {
throw e;
} catch (Exception e) {
@@ -324,8 +340,7 @@
* @param verifyFull whether to verify all contents of this APK or just collect certificates.
* @throws PackageParserException if there was a problem collecting certificates
*/
- private static PackageParser.SigningDetails verifyV1Signature(
- String apkPath, boolean verifyFull)
+ private static SigningDetailsWithDigests verifyV1Signature(String apkPath, boolean verifyFull)
throws PackageParserException {
StrictJarFile jarFile = null;
@@ -391,7 +406,8 @@
}
}
}
- return new PackageParser.SigningDetails(lastSigs, SignatureSchemeVersion.JAR);
+ return new SigningDetailsWithDigests(
+ new PackageParser.SigningDetails(lastSigs, SignatureSchemeVersion.JAR), null);
} catch (GeneralSecurityException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
"Failed to collect certificates from " + apkPath, e);
@@ -542,4 +558,27 @@
return null;
}
}
+
+ /**
+ * Extended signing details.
+ * @hide for internal use only.
+ */
+ public static class SigningDetailsWithDigests {
+ public final PackageParser.SigningDetails signingDetails;
+
+ /**
+ * APK Signature Schemes v2/v3/v4 might contain multiple content digests.
+ * SignatureVerifier usually chooses one of them to verify.
+ * For certain signature schemes, e.g. v4, this digest is verified continuously.
+ * For others, e.g. v2, the caller has to specify if they want to verify.
+ * Please refer to documentation for more details.
+ */
+ public final Map<Integer, byte[]> contentDigests;
+
+ SigningDetailsWithDigests(PackageParser.SigningDetails signingDetails,
+ Map<Integer, byte[]> contentDigests) {
+ this.signingDetails = signingDetails;
+ this.contentDigests = contentDigests;
+ }
+ }
}
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 990092c..021f232 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -39,7 +39,7 @@
*
* @hide for internal use only.
*/
-final class ApkSigningBlockUtils {
+public final class ApkSigningBlockUtils {
private ApkSigningBlockUtils() {
}
@@ -146,6 +146,37 @@
Map<Integer, byte[]> expectedDigests,
FileDescriptor apkFileDescriptor,
SignatureInfo signatureInfo) throws SecurityException {
+ int[] digestAlgorithms = new int[expectedDigests.size()];
+ int digestAlgorithmCount = 0;
+ for (int digestAlgorithm : expectedDigests.keySet()) {
+ digestAlgorithms[digestAlgorithmCount] = digestAlgorithm;
+ digestAlgorithmCount++;
+ }
+ byte[][] actualDigests;
+ try {
+ actualDigests = computeContentDigestsPer1MbChunk(digestAlgorithms, apkFileDescriptor,
+ signatureInfo);
+ } catch (DigestException e) {
+ throw new SecurityException("Failed to compute digest(s) of contents", e);
+ }
+ for (int i = 0; i < digestAlgorithms.length; i++) {
+ int digestAlgorithm = digestAlgorithms[i];
+ byte[] expectedDigest = expectedDigests.get(digestAlgorithm);
+ byte[] actualDigest = actualDigests[i];
+ if (!MessageDigest.isEqual(expectedDigest, actualDigest)) {
+ throw new SecurityException(
+ getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
+ + " digest of contents did not verify");
+ }
+ }
+ }
+
+ /**
+ * Calculate digests using digestAlgorithms for apkFileDescriptor.
+ * This will skip signature block described by signatureInfo.
+ */
+ public static byte[][] computeContentDigestsPer1MbChunk(int[] digestAlgorithms,
+ FileDescriptor apkFileDescriptor, SignatureInfo signatureInfo) throws DigestException {
// We need to verify the integrity of the following three sections of the file:
// 1. Everything up to the start of the APK Signing Block.
// 2. ZIP Central Directory.
@@ -156,6 +187,7 @@
// avoid wasting physical memory. In most APK verification scenarios, the contents of the
// APK are already there in the OS's page cache and thus mmap does not use additional
// physical memory.
+
DataSource beforeApkSigningBlock =
new MemoryMappedFileDataSource(apkFileDescriptor, 0,
signatureInfo.apkSigningBlockOffset);
@@ -171,31 +203,8 @@
ZipUtils.setZipEocdCentralDirectoryOffset(eocdBuf, signatureInfo.apkSigningBlockOffset);
DataSource eocd = new ByteBufferDataSource(eocdBuf);
- int[] digestAlgorithms = new int[expectedDigests.size()];
- int digestAlgorithmCount = 0;
- for (int digestAlgorithm : expectedDigests.keySet()) {
- digestAlgorithms[digestAlgorithmCount] = digestAlgorithm;
- digestAlgorithmCount++;
- }
- byte[][] actualDigests;
- try {
- actualDigests =
- computeContentDigestsPer1MbChunk(
- digestAlgorithms,
- new DataSource[] {beforeApkSigningBlock, centralDir, eocd});
- } catch (DigestException e) {
- throw new SecurityException("Failed to compute digest(s) of contents", e);
- }
- for (int i = 0; i < digestAlgorithms.length; i++) {
- int digestAlgorithm = digestAlgorithms[i];
- byte[] expectedDigest = expectedDigests.get(digestAlgorithm);
- byte[] actualDigest = actualDigests[i];
- if (!MessageDigest.isEqual(expectedDigest, actualDigest)) {
- throw new SecurityException(
- getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
- + " digest of contents did not verify");
- }
- }
+ return computeContentDigestsPer1MbChunk(digestAlgorithms,
+ new DataSource[]{beforeApkSigningBlock, centralDir, eocd});
}
private static byte[][] computeContentDigestsPer1MbChunk(
@@ -417,14 +426,10 @@
static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0423;
static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0425;
- static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
- static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
- static final int CONTENT_DIGEST_VERITY_CHUNKED_SHA256 = 3;
- static final int CONTENT_DIGEST_SHA256 = 4;
-
- private static final int[] V4_CONTENT_DIGEST_ALGORITHMS =
- {CONTENT_DIGEST_CHUNKED_SHA512, CONTENT_DIGEST_VERITY_CHUNKED_SHA256,
- CONTENT_DIGEST_CHUNKED_SHA256};
+ public static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
+ public static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
+ public static final int CONTENT_DIGEST_VERITY_CHUNKED_SHA256 = 3;
+ public static final int CONTENT_DIGEST_SHA256 = 4;
static int compareSignatureAlgorithm(int sigAlgorithm1, int sigAlgorithm2) {
int digestAlgorithm1 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm1);
diff --git a/core/java/android/util/apk/SignatureInfo.java b/core/java/android/util/apk/SignatureInfo.java
index 8e1233a..7638293 100644
--- a/core/java/android/util/apk/SignatureInfo.java
+++ b/core/java/android/util/apk/SignatureInfo.java
@@ -16,15 +16,18 @@
package android.util.apk;
+import android.annotation.NonNull;
+
import java.nio.ByteBuffer;
/**
* APK Signature Scheme v2 block and additional information relevant to verifying the signatures
* contained in the block against the file.
+ * @hide
*/
-class SignatureInfo {
+public class SignatureInfo {
/** Contents of APK Signature Scheme v2 block. */
- public final ByteBuffer signatureBlock;
+ public final @NonNull ByteBuffer signatureBlock;
/** Position of the APK Signing Block in the file. */
public final long apkSigningBlockOffset;
@@ -36,10 +39,10 @@
public final long eocdOffset;
/** Contents of ZIP End of Central Directory (EoCD) of the file. */
- public final ByteBuffer eocd;
+ public final @NonNull ByteBuffer eocd;
- SignatureInfo(ByteBuffer signatureBlock, long apkSigningBlockOffset, long centralDirOffset,
- long eocdOffset, ByteBuffer eocd) {
+ SignatureInfo(@NonNull ByteBuffer signatureBlock, long apkSigningBlockOffset,
+ long centralDirOffset, long eocdOffset, @NonNull ByteBuffer eocd) {
this.signatureBlock = signatureBlock;
this.apkSigningBlockOffset = apkSigningBlockOffset;
this.centralDirOffset = centralDirOffset;
diff --git a/core/java/android/util/apk/VerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java
index e81e3f7..4596c6e 100644
--- a/core/java/android/util/apk/VerityBuilder.java
+++ b/core/java/android/util/apk/VerityBuilder.java
@@ -116,6 +116,34 @@
}
/**
+ * Generates the fs-verity hash tree. It is the actual verity tree format on disk, as is
+ * re-generated on device.
+ *
+ * The tree is built bottom up. The bottom level has 256-bit digest for each 4 KB block in the
+ * input file. If the total size is larger than 4 KB, take this level as input and repeat the
+ * same procedure, until the level is within 4 KB. If salt is given, it will apply to each
+ * digestion before the actual data.
+ *
+ * The returned root hash is calculated from the last level of 4 KB chunk, similarly with salt.
+ *
+ * @return the root hash of the generated hash tree.
+ */
+ public static byte[] generateFsVerityRootHash(@NonNull String apkPath, byte[] salt,
+ @NonNull ByteBufferFactory bufferFactory)
+ throws IOException, NoSuchAlgorithmException, DigestException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+ int[] levelOffset = calculateVerityLevelOffset(apk.length());
+ int merkleTreeSize = levelOffset[levelOffset.length - 1];
+
+ ByteBuffer output = bufferFactory.create(
+ merkleTreeSize
+ + CHUNK_SIZE_BYTES); // maximum size of apk-verity metadata
+ output.order(ByteOrder.LITTLE_ENDIAN);
+ ByteBuffer tree = slice(output, 0, merkleTreeSize);
+ return generateFsVerityTreeInternal(apk, salt, levelOffset, tree);
+ }
+ }
+ /**
* Calculates the apk-verity root hash for integrity measurement. This needs to be consistent
* to what kernel returns.
*/
@@ -259,9 +287,10 @@
// thus the syscall overhead is not too big.
private static final int MMAP_REGION_SIZE_BYTES = 1024 * 1024;
- private static void generateFsVerityDigestAtLeafLevel(RandomAccessFile file, ByteBuffer output)
+ private static void generateFsVerityDigestAtLeafLevel(RandomAccessFile file,
+ @Nullable byte[] salt, ByteBuffer output)
throws IOException, NoSuchAlgorithmException, DigestException {
- BufferedDigester digester = new BufferedDigester(null /* salt */, output);
+ BufferedDigester digester = new BufferedDigester(salt, output);
// 1. Digest the whole file by chunks.
consumeByChunk(digester,
@@ -325,6 +354,35 @@
}
@NonNull
+ private static byte[] generateFsVerityTreeInternal(@NonNull RandomAccessFile apk,
+ @Nullable byte[] salt, @NonNull int[] levelOffset, @NonNull ByteBuffer output)
+ throws IOException, NoSuchAlgorithmException, DigestException {
+ // 1. Digest the apk to generate the leaf level hashes.
+ generateFsVerityDigestAtLeafLevel(apk, salt,
+ slice(output, levelOffset[levelOffset.length - 2],
+ levelOffset[levelOffset.length - 1]));
+
+ // 2. Digest the lower level hashes bottom up.
+ for (int level = levelOffset.length - 3; level >= 0; level--) {
+ ByteBuffer inputBuffer = slice(output, levelOffset[level + 1], levelOffset[level + 2]);
+ ByteBuffer outputBuffer = slice(output, levelOffset[level], levelOffset[level + 1]);
+
+ DataSource source = new ByteBufferDataSource(inputBuffer);
+ BufferedDigester digester = new BufferedDigester(salt, outputBuffer);
+ consumeByChunk(digester, source, CHUNK_SIZE_BYTES);
+ digester.assertEmptyBuffer();
+ digester.fillUpLastOutputChunk();
+ }
+
+ // 3. Digest the first block (i.e. first level) to generate the root hash.
+ byte[] rootHash = new byte[DIGEST_SIZE_BYTES];
+ BufferedDigester digester = new BufferedDigester(salt, ByteBuffer.wrap(rootHash));
+ digester.consume(slice(output, 0, CHUNK_SIZE_BYTES));
+ digester.assertEmptyBuffer();
+ return rootHash;
+ }
+
+ @NonNull
private static byte[] generateVerityTreeInternal(@NonNull RandomAccessFile apk,
@Nullable SignatureInfo signatureInfo, @Nullable byte[] salt,
@NonNull int[] levelOffset, @NonNull ByteBuffer output)
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 6136a80..0c3d61f 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -456,8 +456,8 @@
case MotionEvent.ACTION_UP:
if (mTrackGesture) {
if (mFeedbackIcon.isVisibleToUser()
- && (mFeedbackRect.contains((int) x, (int) y))
- || mFeedbackRect.contains((int) mDownX, (int) mDownY)) {
+ && (mFeedbackRect.contains((int) x, (int) y)
+ || mFeedbackRect.contains((int) mDownX, (int) mDownY))) {
mFeedbackIcon.performClick();
return true;
}
diff --git a/core/java/android/view/inputmethod/TEST_MAPPING b/core/java/android/view/inputmethod/TEST_MAPPING
new file mode 100644
index 0000000..4b2ea1a
--- /dev/null
+++ b/core/java/android/view/inputmethod/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsAutoFillServiceTestCases",
+ "options": [
+ {
+ "include-filter": "android.autofillservice.cts.inline"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.AppModeFull"
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index 92fa80e..12b16ff 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -60,5 +60,6 @@
* Requests that the given task organizer is notified when back is pressed on the root activity
* of one of its controlled tasks.
*/
- void setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer, boolean interceptBackPressed);
+ void setInterceptBackPressedOnTaskRoot(in WindowContainerToken task,
+ boolean interceptBackPressed);
}
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 7ec4f99..38fb023 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -149,9 +149,10 @@
* of one of its controlled tasks.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public void setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed) {
+ public void setInterceptBackPressedOnTaskRoot(@NonNull WindowContainerToken task,
+ boolean interceptBackPressed) {
try {
- getController().setInterceptBackPressedOnTaskRoot(mInterface, interceptBackPressed);
+ getController().setInterceptBackPressedOnTaskRoot(task, interceptBackPressed);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java
index 46c72f8..eb9dfed 100644
--- a/core/java/android/window/TaskOrganizerTaskEmbedder.java
+++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java
@@ -74,7 +74,7 @@
// windowing mode tasks. Plan is to migrate this to a wm-shell front-end when that
// infrastructure is ready.
// mTaskOrganizer.registerOrganizer();
- mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true);
+ // mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true);
return super.onInitialize();
}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index eb59f0f..da26930 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -409,6 +409,11 @@
*/
public static final String BACK_GESTURE_SLOP_MULTIPLIER = "back_gesture_slop_multiplier";
+ /**
+ * (long) Screenshot keychord delay (how long the buttons must be pressed), in ms
+ */
+ public static final String SCREENSHOT_KEYCHORD_DELAY = "screenshot_keychord_delay";
+
private SystemUiDeviceConfigFlags() {
}
}
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index a50a522..3b5fecf 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -113,6 +113,14 @@
// Default is no-op
}
+ /**
+ * Callback indicating that the given document has been deleted or moved. This gives
+ * the provider a hook to revoke the uri permissions.
+ */
+ protected void onDocIdDeleted(String docId) {
+ // Default is no-op
+ }
+
@Override
public boolean onCreate() {
throw new UnsupportedOperationException(
@@ -283,6 +291,7 @@
final String afterDocId = getDocIdForFile(after);
onDocIdChanged(docId);
+ onDocIdDeleted(docId);
onDocIdChanged(afterDocId);
final File afterVisibleFile = getFileForDocId(afterDocId, true);
@@ -312,6 +321,7 @@
final String docId = getDocIdForFile(after);
onDocIdChanged(sourceDocumentId);
+ onDocIdDeleted(sourceDocumentId);
onDocIdChanged(docId);
moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true));
@@ -343,6 +353,7 @@
}
onDocIdChanged(docId);
+ onDocIdDeleted(docId);
removeFromMediaStore(visibleFile);
}
diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
new file mode 100644
index 0000000..8a4eb4a
--- /dev/null
+++ b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
@@ -0,0 +1,397 @@
+/*
+ * 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.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;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogDataType;
+import com.android.internal.util.TraceBuffer;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.IllegalFormatConversionException;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+
+/**
+ * A service for the ProtoLog logging system.
+ */
+public class BaseProtoLogImpl {
+ protected static final TreeMap<String, IProtoLogGroup> LOG_GROUPS = new TreeMap<>();
+
+ /**
+ * A runnable to update the cached output of {@link #isEnabled}.
+ *
+ * Must be invoked after every action that could change the result of {@link #isEnabled}, eg.
+ * starting / stopping proto log, or enabling / disabling log groups.
+ */
+ public static Runnable sCacheUpdater = () -> { };
+
+ protected static void addLogGroupEnum(IProtoLogGroup[] config) {
+ for (IProtoLogGroup group : config) {
+ LOG_GROUPS.put(group.name(), group);
+ }
+ }
+
+ private static final String TAG = "ProtoLog";
+ private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+ static final String PROTOLOG_VERSION = "1.0.0";
+
+ private final File mLogFile;
+ private final String mViewerConfigFilename;
+ private final TraceBuffer mBuffer;
+ protected final ProtoLogViewerConfigReader mViewerConfig;
+
+ private boolean mProtoLogEnabled;
+ private boolean mProtoLogEnabledLockFree;
+ private final Object mProtoLogEnabledLock = new Object();
+
+ @VisibleForTesting
+ public enum LogLevel {
+ DEBUG, VERBOSE, INFO, WARN, ERROR, WTF
+ }
+
+ /**
+ * Main log method, do not call directly.
+ */
+ @VisibleForTesting
+ public void log(LogLevel level, IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString, Object[] args) {
+ if (group.isLogToProto()) {
+ logToProto(messageHash, paramsMask, args);
+ }
+ if (group.isLogToLogcat()) {
+ logToLogcat(group.getTag(), level, messageHash, messageString, args);
+ }
+ }
+
+ private void logToLogcat(String tag, LogLevel level, int messageHash,
+ @Nullable String messageString, Object[] args) {
+ String message = null;
+ if (messageString == null) {
+ messageString = mViewerConfig.getViewerString(messageHash);
+ }
+ if (messageString != null) {
+ try {
+ message = String.format(messageString, args);
+ } catch (IllegalFormatConversionException ex) {
+ Slog.w(TAG, "Invalid ProtoLog format string.", ex);
+ }
+ }
+ if (message == null) {
+ StringBuilder builder = new StringBuilder("UNKNOWN MESSAGE (" + messageHash + ")");
+ for (Object o : args) {
+ builder.append(" ").append(o);
+ }
+ message = builder.toString();
+ }
+ passToLogcat(tag, level, message);
+ }
+
+ /**
+ * SLog wrapper.
+ */
+ @VisibleForTesting
+ public void passToLogcat(String tag, LogLevel level, String message) {
+ switch (level) {
+ case DEBUG:
+ Slog.d(tag, message);
+ break;
+ case VERBOSE:
+ Slog.v(tag, message);
+ break;
+ case INFO:
+ Slog.i(tag, message);
+ break;
+ case WARN:
+ Slog.w(tag, message);
+ break;
+ case ERROR:
+ Slog.e(tag, message);
+ break;
+ case WTF:
+ Slog.wtf(tag, message);
+ break;
+ }
+ }
+
+ private void logToProto(int messageHash, int paramsMask, Object[] args) {
+ if (!isProtoEnabled()) {
+ return;
+ }
+ try {
+ ProtoOutputStream os = new ProtoOutputStream();
+ long token = os.start(LOG);
+ os.write(MESSAGE_HASH, messageHash);
+ os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+
+ if (args != null) {
+ int argIndex = 0;
+ ArrayList<Long> longParams = new ArrayList<>();
+ ArrayList<Double> doubleParams = new ArrayList<>();
+ ArrayList<Boolean> booleanParams = new ArrayList<>();
+ for (Object o : args) {
+ int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex);
+ try {
+ switch (type) {
+ case LogDataType.STRING:
+ os.write(STR_PARAMS, o.toString());
+ break;
+ case LogDataType.LONG:
+ longParams.add(((Number) o).longValue());
+ break;
+ case LogDataType.DOUBLE:
+ doubleParams.add(((Number) o).doubleValue());
+ break;
+ case LogDataType.BOOLEAN:
+ booleanParams.add((boolean) o);
+ break;
+ }
+ } catch (ClassCastException ex) {
+ // Should not happen unless there is an error in the ProtoLogTool.
+ os.write(STR_PARAMS, "(INVALID PARAMS_MASK) " + o.toString());
+ Slog.e(TAG, "Invalid ProtoLog paramsMask", ex);
+ }
+ argIndex++;
+ }
+ if (longParams.size() > 0) {
+ os.writePackedSInt64(SINT64_PARAMS,
+ longParams.stream().mapToLong(i -> i).toArray());
+ }
+ if (doubleParams.size() > 0) {
+ os.writePackedDouble(DOUBLE_PARAMS,
+ doubleParams.stream().mapToDouble(i -> i).toArray());
+ }
+ if (booleanParams.size() > 0) {
+ boolean[] arr = new boolean[booleanParams.size()];
+ for (int i = 0; i < booleanParams.size(); i++) {
+ arr[i] = booleanParams.get(i);
+ }
+ os.writePackedBool(BOOLEAN_PARAMS, arr);
+ }
+ }
+ os.end(token);
+ mBuffer.add(os);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception while logging to proto", e);
+ }
+ }
+
+ public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
+ ProtoLogViewerConfigReader viewerConfig) {
+ mLogFile = file;
+ mBuffer = new TraceBuffer(bufferCapacity);
+ mViewerConfigFilename = viewerConfigFilename;
+ mViewerConfig = viewerConfig;
+ }
+
+ /**
+ * Starts the logging a circular proto buffer.
+ *
+ * @param pw Print writer
+ */
+ public void startProtoLog(@Nullable PrintWriter pw) {
+ if (isProtoEnabled()) {
+ return;
+ }
+ synchronized (mProtoLogEnabledLock) {
+ logAndPrintln(pw, "Start logging to " + mLogFile + ".");
+ mBuffer.resetBuffer();
+ mProtoLogEnabled = true;
+ mProtoLogEnabledLockFree = true;
+ }
+ sCacheUpdater.run();
+ }
+
+ /**
+ * Stops logging to proto.
+ *
+ * @param pw Print writer
+ * @param writeToFile If the current buffer should be written to disk or not
+ */
+ public void stopProtoLog(@Nullable PrintWriter pw, boolean writeToFile) {
+ if (!isProtoEnabled()) {
+ return;
+ }
+ synchronized (mProtoLogEnabledLock) {
+ logAndPrintln(pw, "Stop logging to " + mLogFile + ". Waiting for log to flush.");
+ mProtoLogEnabled = mProtoLogEnabledLockFree = false;
+ if (writeToFile) {
+ writeProtoLogToFileLocked();
+ logAndPrintln(pw, "Log written to " + mLogFile + ".");
+ }
+ if (mProtoLogEnabled) {
+ logAndPrintln(pw, "ERROR: logging was re-enabled while waiting for flush.");
+ throw new IllegalStateException("logging enabled while waiting for flush.");
+ }
+ }
+ sCacheUpdater.run();
+ }
+
+ /**
+ * Returns {@code true} iff logging to proto is enabled.
+ */
+ public boolean isProtoEnabled() {
+ return mProtoLogEnabledLockFree;
+ }
+
+ protected int setLogging(boolean setTextLogging, boolean value, PrintWriter pw,
+ String... groups) {
+ for (int i = 0; i < groups.length; i++) {
+ String group = groups[i];
+ IProtoLogGroup g = LOG_GROUPS.get(group);
+ if (g != null) {
+ System.out.println("G: "+ g);
+ if (setTextLogging) {
+ g.setLogToLogcat(value);
+ } else {
+ g.setLogToProto(value);
+ }
+ } else {
+ logAndPrintln(pw, "No IProtoLogGroup named " + group);
+ return -1;
+ }
+ }
+ sCacheUpdater.run();
+ return 0;
+ }
+
+ private int unknownCommand(PrintWriter pw) {
+ pw.println("Unknown command");
+ pw.println("Window manager logging options:");
+ pw.println(" start: Start proto logging");
+ pw.println(" stop: Stop proto logging");
+ pw.println(" enable [group...]: Enable proto logging for given groups");
+ pw.println(" disable [group...]: Disable proto logging for given groups");
+ pw.println(" enable-text [group...]: Enable logcat logging for given groups");
+ pw.println(" disable-text [group...]: Disable logcat logging for given groups");
+ return -1;
+ }
+
+ /**
+ * Responds to a shell command.
+ */
+ public int onShellCommand(ShellCommand shell) {
+ PrintWriter pw = shell.getOutPrintWriter();
+ String cmd = shell.getNextArg();
+ if (cmd == null) {
+ return unknownCommand(pw);
+ }
+ ArrayList<String> args = new ArrayList<>();
+ String arg;
+ while ((arg = shell.getNextArg()) != null) {
+ args.add(arg);
+ }
+ String[] groups = args.toArray(new String[args.size()]);
+ switch (cmd) {
+ case "start":
+ startProtoLog(pw);
+ return 0;
+ case "stop":
+ stopProtoLog(pw, true);
+ return 0;
+ case "status":
+ logAndPrintln(pw, getStatus());
+ return 0;
+ case "enable":
+ return setLogging(false, true, pw, groups);
+ case "enable-text":
+ mViewerConfig.loadViewerConfig(pw, mViewerConfigFilename);
+ return setLogging(true, true, pw, groups);
+ case "disable":
+ return setLogging(false, false, pw, groups);
+ case "disable-text":
+ return setLogging(true, false, pw, groups);
+ default:
+ return unknownCommand(pw);
+ }
+ }
+
+ /**
+ * Returns a human-readable ProtoLog status text.
+ */
+ public String getStatus() {
+ return "ProtoLog status: "
+ + ((isProtoEnabled()) ? "Enabled" : "Disabled")
+ + "\nEnabled log groups: \n Proto: "
+ + LOG_GROUPS.values().stream().filter(
+ it -> it.isEnabled() && it.isLogToProto())
+ .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
+ + "\n Logcat: "
+ + LOG_GROUPS.values().stream().filter(
+ it -> it.isEnabled() && it.isLogToLogcat())
+ .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
+ + "\nLogging definitions loaded: " + mViewerConfig.knownViewerStringsNumber();
+ }
+
+ /**
+ * Writes the log buffer to a new file for the bugreport.
+ *
+ * This method is synchronized with {@code #startProtoLog(PrintWriter)} and
+ * {@link #stopProtoLog(PrintWriter, boolean)}.
+ */
+ public void writeProtoLogToFile() {
+ synchronized (mProtoLogEnabledLock) {
+ writeProtoLogToFileLocked();
+ }
+ }
+
+ private void writeProtoLogToFileLocked() {
+ try {
+ long offset =
+ (System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() / 1000000));
+ ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ proto.write(VERSION, PROTOLOG_VERSION);
+ proto.write(REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS, offset);
+ mBuffer.writeTraceToFile(mLogFile, proto);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to write buffer to file", e);
+ }
+ }
+
+ static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+ Slog.i(TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
+ }
+ }
+}
+
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 0834b2d..9f7436a 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -70,6 +70,8 @@
Consts.TAG_WM),
WM_DEBUG_IME(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
+ WM_DEBUG_WINDOW_ORGANIZER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
TEST_GROUP(true, true, false, "WindowManagetProtoLogTest");
private final boolean mEnabled;
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index 6874f10..10224a4 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -16,58 +16,22 @@
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;
-import android.os.SystemClock;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.IProtoLogGroup;
-import com.android.internal.protolog.common.LogDataType;
-import com.android.internal.util.TraceBuffer;
import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.IllegalFormatConversionException;
-import java.util.TreeMap;
-import java.util.stream.Collectors;
-
/**
* A service for the ProtoLog logging system.
*/
-public class ProtoLogImpl {
- private static final TreeMap<String, IProtoLogGroup> LOG_GROUPS = new TreeMap<>();
+public class ProtoLogImpl extends BaseProtoLogImpl {
+ private static final int BUFFER_CAPACITY = 1024 * 1024;
+ private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.pb";
+ private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz";
- /**
- * A runnable to update the cached output of {@link #isEnabled}.
- *
- * Must be invoked after every action that could change the result of {@link #isEnabled}, eg.
- * starting / stopping proto log, or enabling / disabling log groups.
- */
- public static Runnable sCacheUpdater = () -> { };
-
- private static void addLogGroupEnum(IProtoLogGroup[] config) {
- for (IProtoLogGroup group : config) {
- LOG_GROUPS.put(group.name(), group);
- }
- }
+ private static ProtoLogImpl sServiceInstance = null;
static {
addLogGroupEnum(ProtoLogGroup.values());
@@ -124,30 +88,13 @@
|| (group.isLogToProto() && getSingleInstance().isProtoEnabled());
}
- private static final int BUFFER_CAPACITY = 1024 * 1024;
- private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.pb";
- private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz";
- private static final String TAG = "ProtoLog";
- private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
- static final String PROTOLOG_VERSION = "1.0.0";
-
- private final File mLogFile;
- private final TraceBuffer mBuffer;
- private final ProtoLogViewerConfigReader mViewerConfig;
-
- private boolean mProtoLogEnabled;
- private boolean mProtoLogEnabledLockFree;
- private final Object mProtoLogEnabledLock = new Object();
-
- private static ProtoLogImpl sServiceInstance = null;
-
/**
* Returns the single instance of the ProtoLogImpl singleton class.
*/
public static synchronized ProtoLogImpl getSingleInstance() {
if (sServiceInstance == null) {
- sServiceInstance = new ProtoLogImpl(new File(LOG_FILENAME), BUFFER_CAPACITY,
- new ProtoLogViewerConfigReader());
+ sServiceInstance = new ProtoLogImpl(
+ new File(LOG_FILENAME), BUFFER_CAPACITY, new ProtoLogViewerConfigReader());
}
return sServiceInstance;
}
@@ -157,307 +104,9 @@
sServiceInstance = instance;
}
- @VisibleForTesting
- public enum LogLevel {
- DEBUG, VERBOSE, INFO, WARN, ERROR, WTF
- }
-
- /**
- * Main log method, do not call directly.
- */
- @VisibleForTesting
- public void log(LogLevel level, IProtoLogGroup group, int messageHash, int paramsMask,
- @Nullable String messageString, Object[] args) {
- if (group.isLogToProto()) {
- logToProto(messageHash, paramsMask, args);
- }
- if (group.isLogToLogcat()) {
- logToLogcat(group.getTag(), level, messageHash, messageString, args);
- }
- }
-
- private void logToLogcat(String tag, LogLevel level, int messageHash,
- @Nullable String messageString, Object[] args) {
- String message = null;
- if (messageString == null) {
- messageString = mViewerConfig.getViewerString(messageHash);
- }
- if (messageString != null) {
- try {
- message = String.format(messageString, args);
- } catch (IllegalFormatConversionException ex) {
- Slog.w(TAG, "Invalid ProtoLog format string.", ex);
- }
- }
- if (message == null) {
- StringBuilder builder = new StringBuilder("UNKNOWN MESSAGE (" + messageHash + ")");
- for (Object o : args) {
- builder.append(" ").append(o);
- }
- message = builder.toString();
- }
- passToLogcat(tag, level, message);
- }
-
- /**
- * SLog wrapper.
- */
- @VisibleForTesting
- public void passToLogcat(String tag, LogLevel level, String message) {
- switch (level) {
- case DEBUG:
- Slog.d(tag, message);
- break;
- case VERBOSE:
- Slog.v(tag, message);
- break;
- case INFO:
- Slog.i(tag, message);
- break;
- case WARN:
- Slog.w(tag, message);
- break;
- case ERROR:
- Slog.e(tag, message);
- break;
- case WTF:
- Slog.wtf(tag, message);
- break;
- }
- }
-
- private void logToProto(int messageHash, int paramsMask, Object[] args) {
- if (!isProtoEnabled()) {
- return;
- }
- try {
- ProtoOutputStream os = new ProtoOutputStream();
- long token = os.start(LOG);
- os.write(MESSAGE_HASH, messageHash);
- os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
-
- if (args != null) {
- int argIndex = 0;
- ArrayList<Long> longParams = new ArrayList<>();
- ArrayList<Double> doubleParams = new ArrayList<>();
- ArrayList<Boolean> booleanParams = new ArrayList<>();
- for (Object o : args) {
- int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex);
- try {
- switch (type) {
- case LogDataType.STRING:
- os.write(STR_PARAMS, o.toString());
- break;
- case LogDataType.LONG:
- longParams.add(((Number) o).longValue());
- break;
- case LogDataType.DOUBLE:
- doubleParams.add(((Number) o).doubleValue());
- break;
- case LogDataType.BOOLEAN:
- booleanParams.add((boolean) o);
- break;
- }
- } catch (ClassCastException ex) {
- // Should not happen unless there is an error in the ProtoLogTool.
- os.write(STR_PARAMS, "(INVALID PARAMS_MASK) " + o.toString());
- Slog.e(TAG, "Invalid ProtoLog paramsMask", ex);
- }
- argIndex++;
- }
- if (longParams.size() > 0) {
- os.writePackedSInt64(SINT64_PARAMS,
- longParams.stream().mapToLong(i -> i).toArray());
- }
- if (doubleParams.size() > 0) {
- os.writePackedDouble(DOUBLE_PARAMS,
- doubleParams.stream().mapToDouble(i -> i).toArray());
- }
- if (booleanParams.size() > 0) {
- boolean[] arr = new boolean[booleanParams.size()];
- for (int i = 0; i < booleanParams.size(); i++) {
- arr[i] = booleanParams.get(i);
- }
- os.writePackedBool(BOOLEAN_PARAMS, arr);
- }
- }
- os.end(token);
- mBuffer.add(os);
- } catch (Exception e) {
- Slog.e(TAG, "Exception while logging to proto", e);
- }
- }
-
- public ProtoLogImpl(File file, int bufferCapacity, ProtoLogViewerConfigReader viewerConfig) {
- mLogFile = file;
- mBuffer = new TraceBuffer(bufferCapacity);
- mViewerConfig = viewerConfig;
- }
-
- /**
- * Starts the logging a circular proto buffer.
- *
- * @param pw Print writer
- */
- public void startProtoLog(@Nullable PrintWriter pw) {
- if (isProtoEnabled()) {
- return;
- }
- synchronized (mProtoLogEnabledLock) {
- logAndPrintln(pw, "Start logging to " + mLogFile + ".");
- mBuffer.resetBuffer();
- mProtoLogEnabled = true;
- mProtoLogEnabledLockFree = true;
- }
- sCacheUpdater.run();
- }
-
- /**
- * Stops logging to proto.
- *
- * @param pw Print writer
- * @param writeToFile If the current buffer should be written to disk or not
- */
- public void stopProtoLog(@Nullable PrintWriter pw, boolean writeToFile) {
- if (!isProtoEnabled()) {
- return;
- }
- synchronized (mProtoLogEnabledLock) {
- logAndPrintln(pw, "Stop logging to " + mLogFile + ". Waiting for log to flush.");
- mProtoLogEnabled = mProtoLogEnabledLockFree = false;
- if (writeToFile) {
- writeProtoLogToFileLocked();
- logAndPrintln(pw, "Log written to " + mLogFile + ".");
- }
- if (mProtoLogEnabled) {
- logAndPrintln(pw, "ERROR: logging was re-enabled while waiting for flush.");
- throw new IllegalStateException("logging enabled while waiting for flush.");
- }
- }
- sCacheUpdater.run();
- }
-
- /**
- * Returns {@code true} iff logging to proto is enabled.
- */
- public boolean isProtoEnabled() {
- return mProtoLogEnabledLockFree;
- }
-
- private int setLogging(ShellCommand shell, boolean setTextLogging, boolean value) {
- String group;
- while ((group = shell.getNextArg()) != null) {
- IProtoLogGroup g = LOG_GROUPS.get(group);
- if (g != null) {
- if (setTextLogging) {
- g.setLogToLogcat(value);
- } else {
- g.setLogToProto(value);
- }
- } else {
- logAndPrintln(shell.getOutPrintWriter(), "No IProtoLogGroup named " + group);
- return -1;
- }
- }
- sCacheUpdater.run();
- return 0;
- }
-
- private int unknownCommand(PrintWriter pw) {
- pw.println("Unknown command");
- pw.println("Window manager logging options:");
- pw.println(" start: Start proto logging");
- pw.println(" stop: Stop proto logging");
- pw.println(" enable [group...]: Enable proto logging for given groups");
- pw.println(" disable [group...]: Disable proto logging for given groups");
- pw.println(" enable-text [group...]: Enable logcat logging for given groups");
- pw.println(" disable-text [group...]: Disable logcat logging for given groups");
- return -1;
- }
-
- /**
- * Responds to a shell command.
- */
- public int onShellCommand(ShellCommand shell) {
- PrintWriter pw = shell.getOutPrintWriter();
- String cmd = shell.getNextArg();
- if (cmd == null) {
- return unknownCommand(pw);
- }
- switch (cmd) {
- case "start":
- startProtoLog(pw);
- return 0;
- case "stop":
- stopProtoLog(pw, true);
- return 0;
- case "status":
- logAndPrintln(pw, getStatus());
- return 0;
- case "enable":
- return setLogging(shell, false, true);
- case "enable-text":
- mViewerConfig.loadViewerConfig(pw, VIEWER_CONFIG_FILENAME);
- return setLogging(shell, true, true);
- case "disable":
- return setLogging(shell, false, false);
- case "disable-text":
- return setLogging(shell, true, false);
- default:
- return unknownCommand(pw);
- }
- }
-
- /**
- * Returns a human-readable ProtoLog status text.
- */
- public String getStatus() {
- return "ProtoLog status: "
- + ((isProtoEnabled()) ? "Enabled" : "Disabled")
- + "\nEnabled log groups: \n Proto: "
- + LOG_GROUPS.values().stream().filter(
- it -> it.isEnabled() && it.isLogToProto())
- .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
- + "\n Logcat: "
- + LOG_GROUPS.values().stream().filter(
- it -> it.isEnabled() && it.isLogToLogcat())
- .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
- + "\nLogging definitions loaded: " + mViewerConfig.knownViewerStringsNumber();
- }
-
- /**
- * Writes the log buffer to a new file for the bugreport.
- *
- * This method is synchronized with {@code #startProtoLog(PrintWriter)} and
- * {@link #stopProtoLog(PrintWriter, boolean)}.
- */
- public void writeProtoLogToFile() {
- synchronized (mProtoLogEnabledLock) {
- writeProtoLogToFileLocked();
- }
- }
-
- private void writeProtoLogToFileLocked() {
- try {
- long offset =
- (System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() / 1000000));
- ProtoOutputStream proto = new ProtoOutputStream();
- proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
- proto.write(VERSION, PROTOLOG_VERSION);
- proto.write(REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS, offset);
- mBuffer.writeTraceToFile(mLogFile, proto);
- } catch (IOException e) {
- Slog.e(TAG, "Unable to write buffer to file", e);
- }
- }
-
-
- static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
- Slog.i(TAG, msg);
- if (pw != null) {
- pw.println(msg);
- pw.flush();
- }
+ public ProtoLogImpl(File logFile, int bufferCapacity,
+ ProtoLogViewerConfigReader viewConfigReader) {
+ super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader);
}
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
index e381d30..aa30a77 100644
--- a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
+++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
@@ -16,6 +16,9 @@
package com.android.internal.protolog;
+import android.annotation.Nullable;
+import android.util.Slog;
+
import org.json.JSONException;
import org.json.JSONObject;
@@ -23,6 +26,7 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Iterator;
@@ -34,6 +38,7 @@
* Handles loading and parsing of ProtoLog viewer configuration.
*/
public class ProtoLogViewerConfigReader {
+ private static final String TAG = "ProtoLogViewerConfigReader";
private Map<Integer, String> mLogMessageMap = null;
/** Returns message format string for its hash or null if unavailable. */
@@ -49,48 +54,54 @@
* Reads the specified viewer configuration file. Does nothing if the config is already loaded.
*/
public synchronized void loadViewerConfig(PrintWriter pw, String viewerConfigFilename) {
+ try {
+ loadViewerConfig(new GZIPInputStream(new FileInputStream(viewerConfigFilename)));
+ logAndPrintln(pw, "Loaded " + mLogMessageMap.size()
+ + " log definitions from " + viewerConfigFilename);
+ } catch (FileNotFoundException e) {
+ 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 "
+ + viewerConfigFilename + ". " + e);
+ } catch (JSONException e) {
+ logAndPrintln(pw, "Unable to load log definitions: JSON parsing exception while reading "
+ + viewerConfigFilename + ". " + e);
+ }
+ }
+
+ /**
+ * Reads the specified viewer configuration input stream.
+ * Does nothing if the config is already loaded.
+ */
+ public synchronized void loadViewerConfig(InputStream viewerConfigInputStream)
+ throws IOException, JSONException {
if (mLogMessageMap != null) {
return;
}
- try {
- InputStreamReader config = new InputStreamReader(
- new GZIPInputStream(new FileInputStream(viewerConfigFilename)));
- BufferedReader reader = new BufferedReader(config);
- StringBuilder builder = new StringBuilder();
- String line;
- while ((line = reader.readLine()) != null) {
- builder.append(line).append('\n');
- }
- reader.close();
- JSONObject json = new JSONObject(builder.toString());
- JSONObject messages = json.getJSONObject("messages");
+ InputStreamReader config = new InputStreamReader(viewerConfigInputStream);
+ BufferedReader reader = new BufferedReader(config);
+ StringBuilder builder = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ builder.append(line).append('\n');
+ }
+ reader.close();
+ JSONObject json = new JSONObject(builder.toString());
+ JSONObject messages = json.getJSONObject("messages");
- mLogMessageMap = new TreeMap<>();
- Iterator it = messages.keys();
- while (it.hasNext()) {
- String key = (String) it.next();
- try {
- int hash = Integer.parseInt(key);
- JSONObject val = messages.getJSONObject(key);
- String msg = val.getString("message");
- mLogMessageMap.put(hash, msg);
- } catch (NumberFormatException expected) {
- // Not a messageHash - skip it
- }
+ mLogMessageMap = new TreeMap<>();
+ Iterator it = messages.keys();
+ while (it.hasNext()) {
+ String key = (String) it.next();
+ try {
+ int hash = Integer.parseInt(key);
+ JSONObject val = messages.getJSONObject(key);
+ String msg = val.getString("message");
+ mLogMessageMap.put(hash, msg);
+ } catch (NumberFormatException expected) {
+ // Not a messageHash - skip it
}
- ProtoLogImpl.logAndPrintln(pw, "Loaded " + mLogMessageMap.size()
- + " log definitions from " + viewerConfigFilename);
- } catch (FileNotFoundException e) {
- ProtoLogImpl.logAndPrintln(pw, "Unable to load log definitions: File "
- + viewerConfigFilename + " not found." + e);
- } catch (IOException e) {
- ProtoLogImpl.logAndPrintln(pw,
- "Unable to load log definitions: IOException while reading "
- + viewerConfigFilename + ". " + e);
- } catch (JSONException e) {
- ProtoLogImpl.logAndPrintln(pw,
- "Unable to load log definitions: JSON parsing exception while reading "
- + viewerConfigFilename + ". " + e);
}
}
@@ -103,4 +114,12 @@
}
return 0;
}
+
+ static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+ Slog.i(TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
+ }
+ }
}
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 9ad4cd9..859b40a 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -501,6 +501,15 @@
"Failed to read from parcel (error code %d)", err);
return;
}
+
+ // Update vendor descriptor cache if necessary
+ auto vendorId = metadata->getVendorId();
+ if ((vendorId != CAMERA_METADATA_INVALID_VENDOR_ID) &&
+ !VendorTagDescriptorCache::isVendorCachePresent(vendorId)) {
+ ALOGW("%s: Tag vendor id missing or cache not initialized, trying to update!",
+ __FUNCTION__);
+ CameraMetadata_setupGlobalVendorTagDescriptor(env, thiz);
+ }
}
static void CameraMetadata_writeToParcel(JNIEnv *env, jclass thiz, jobject parcel, jlong ptr) {
@@ -642,9 +651,7 @@
CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(ptr);
metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
if (metadata) {
- const camera_metadata_t *metaBuffer = metadata->getAndLock();
- vendorId = get_camera_metadata_vendor_id(metaBuffer);
- metadata->unlock(metaBuffer);
+ vendorId = metadata->getVendorId();
}
int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
@@ -673,9 +680,7 @@
if (metadata) {
sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
if (cache.get()) {
- const camera_metadata_t *metaBuffer = metadata->getAndLock();
- metadata_vendor_id_t vendorId = get_camera_metadata_vendor_id(metaBuffer);
- metadata->unlock(metaBuffer);
+ auto vendorId = metadata->getVendorId();
cache->getVendorTagDescriptor(vendorId, &vTags);
}
}
@@ -703,10 +708,8 @@
CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
if (metadata == NULL) return NULL;
- const camera_metadata_t *metaBuffer = metadata->getAndLock();
- vendorId = get_camera_metadata_vendor_id(metaBuffer);
+ vendorId = metadata->getVendorId();
cache->getVendorTagDescriptor(vendorId, &vTags);
- metadata->unlock(metaBuffer);
if (vTags.get() == nullptr) {
return nullptr;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 57c1fcf..cdcb24b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3094,7 +3094,8 @@
android:protectionLevel="signature" />
<!-- Allows an application to be the status bar. Currently used only by SystemUI.apk
- @hide -->
+ @hide
+ @SystemApi -->
<permission android:name="android.permission.STATUS_BAR_SERVICE"
android:protectionLevel="signature" />
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 03f7be7..75eb7b6 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -43,6 +43,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-2049725903": {
+ "message": "Task back pressed on root taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"-2039580386": {
"message": "Attempted to add input method window with unknown token %s. Aborting.",
"level": "WARN",
@@ -85,6 +91,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/TaskSnapshotSurface.java"
},
+ "-1980468143": {
+ "message": "DisplayArea appeared name=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"-1976930686": {
"message": "Attempted to add Accessibility overlay window with bad token %s. Aborting.",
"level": "WARN",
@@ -103,6 +115,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1939861963": {
+ "message": "Create root task displayId=%d winMode=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"-1939358269": {
"message": "mRecentScreenshotAnimator finish",
"level": "DEBUG",
@@ -127,6 +145,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1895337367": {
+ "message": "Delete root task display=%d winMode=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"-1884933373": {
"message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
"level": "INFO",
@@ -187,6 +211,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
+ "-1792633344": {
+ "message": "Register task organizer=%s uid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"-1791031393": {
"message": "Ensuring correct configuration: %s",
"level": "VERBOSE",
@@ -421,6 +451,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1364754753": {
+ "message": "Task vanished taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"-1352076759": {
"message": "Removing app token: %s",
"level": "VERBOSE",
@@ -643,6 +679,18 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-951939129": {
+ "message": "Unregister task organizer=%s uid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
+ "-930893991": {
+ "message": "Set sync ready, syncId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+ },
"-929676529": {
"message": "Configuration changes for %s, allChanges=%s",
"level": "VERBOSE",
@@ -793,12 +841,6 @@
"group": "WM_DEBUG_FOCUS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "-714291355": {
- "message": "Losing delayed focus: %s",
- "level": "INFO",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"-694710814": {
"message": "Pausing rotation during drag",
"level": "DEBUG",
@@ -919,6 +961,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
},
+ "-497620140": {
+ "message": "Transaction ready, syncId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+ },
"-496681057": {
"message": "Attempted to get remove mode of a display that does not exist: %d",
"level": "WARN",
@@ -1345,6 +1393,12 @@
"group": "WM_SHOW_SURFACE_ALLOC",
"at": "com\/android\/server\/wm\/BlackFrame.java"
},
+ "174572959": {
+ "message": "DisplayArea info changed name=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"184362060": {
"message": "screenshotTask(%d): mCanceled=%b",
"level": "DEBUG",
@@ -1387,6 +1441,12 @@
"group": "WM_DEBUG_KEEP_SCREEN_ON",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "232317536": {
+ "message": "Set intercept back pressed on root=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"241961619": {
"message": "Adding %s to %s",
"level": "VERBOSE",
@@ -1405,6 +1465,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "251812577": {
+ "message": "Register display organizer=%s uid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"254883724": {
"message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d",
"level": "WARN",
@@ -1453,6 +1519,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "302969511": {
+ "message": "Task info changed taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"302992539": {
"message": "addAnimation(%s)",
"level": "DEBUG",
@@ -1519,12 +1591,6 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "385096046": {
- "message": "Delaying loss of focus...",
- "level": "INFO",
- "group": "WM_DEBUG_FOCUS_LIGHT",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"399841913": {
"message": "SURFACE RECOVER DESTROY: %s",
"level": "INFO",
@@ -1573,6 +1639,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "487621047": {
+ "message": "DisplayArea vanished name=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"490877640": {
"message": "onStackOrderChanged(): stack=%s",
"level": "DEBUG",
@@ -1849,6 +1921,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "906215061": {
+ "message": "Apply window transaction, syncId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+ },
"913494177": {
"message": "removeAllWindowsIfPossible: removing win=%s",
"level": "WARN",
@@ -1957,6 +2035,12 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/DisplayPolicy.java"
},
+ "1149424314": {
+ "message": "Unregister display organizer=%s uid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+ },
"1160771501": {
"message": "Resize reasons for w=%s: %s surfaceResized=%b configChanged=%b dragResizingChanged=%b reportOrientationChanged=%b",
"level": "VERBOSE",
@@ -2443,6 +2527,12 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1918448345": {
+ "message": "Task appeared taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+ },
"1921821199": {
"message": "Preserving %s until the new one is added",
"level": "VERBOSE",
@@ -2676,6 +2766,9 @@
"WM_DEBUG_WINDOW_MOVEMENT": {
"tag": "WindowManager"
},
+ "WM_DEBUG_WINDOW_ORGANIZER": {
+ "tag": "WindowManager"
+ },
"WM_ERROR": {
"tag": "WindowManager"
},
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 843b177..307b82e 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -12,14 +12,88 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// Begin ProtoLog
+java_library {
+ name: "wm_shell_protolog-groups",
+ srcs: [
+ "src/com/android/wm/shell/protolog/ShellProtoLogGroup.java",
+ ":protolog-common-src",
+ ],
+}
+
+filegroup {
+ name: "wm_shell-sources",
+ srcs: ["src/**/*.java"],
+ path: "src",
+}
+
+genrule {
+ name: "wm_shell_protolog_src",
+ srcs: [
+ ":wm_shell_protolog-groups",
+ ":wm_shell-sources",
+ ],
+ tools: ["protologtool"],
+ cmd: "$(location protologtool) transform-protolog-calls " +
+ "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " +
+ "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " +
+ "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
+ "--loggroups-jar $(location :wm_shell_protolog-groups) " +
+ "--output-srcjar $(out) " +
+ "$(locations :wm_shell-sources)",
+ out: ["wm_shell_protolog.srcjar"],
+}
+
+genrule {
+ name: "generate-wm_shell_protolog.json",
+ srcs: [
+ ":wm_shell_protolog-groups",
+ ":wm_shell-sources",
+ ],
+ tools: ["protologtool"],
+ cmd: "$(location protologtool) generate-viewer-config " +
+ "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
+ "--loggroups-jar $(location :wm_shell_protolog-groups) " +
+ "--viewer-conf $(out) " +
+ "$(locations :wm_shell-sources)",
+ out: ["wm_shell_protolog.json"],
+}
+
+filegroup {
+ name: "wm_shell_protolog.json",
+ srcs: ["res/raw/wm_shell_protolog.json"],
+}
+
+genrule {
+ name: "checked-wm_shell_protolog.json",
+ srcs: [
+ ":generate-wm_shell_protolog.json",
+ ":wm_shell_protolog.json",
+ ],
+ cmd: "cp $(location :generate-wm_shell_protolog.json) $(out) && " +
+ "{ ! (diff $(out) $(location :wm_shell_protolog.json) | grep -q '^<') || " +
+ "{ echo -e '\\n\\n################################################################\\n#\\n" +
+ "# ERROR: ProtoLog viewer config is stale. To update it, run:\\n#\\n" +
+ "# cp $(location :generate-wm_shell_protolog.json) " +
+ "$(location :wm_shell_protolog.json)\\n#\\n" +
+ "################################################################\\n\\n' >&2 && false; } }",
+ out: ["wm_shell_protolog.json"],
+}
+// End ProtoLog
+
android_library {
name: "WindowManager-Shell",
srcs: [
- "src/**/*.java",
+ ":wm_shell_protolog_src",
"src/**/I*.aidl",
],
resource_dirs: [
"res",
],
+ static_libs: [
+ "protolog-lib",
+ ],
manifest: "AndroidManifest.xml",
-}
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/pip_menu_activity.xml b/libs/WindowManager/Shell/res/layout/pip_menu.xml
similarity index 100%
rename from libs/WindowManager/Shell/res/layout/pip_menu_activity.xml
rename to libs/WindowManager/Shell/res/layout/pip_menu.xml
diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
new file mode 100644
index 0000000..7242793
--- /dev/null
+++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
@@ -0,0 +1,46 @@
+{
+ "version": "1.0.0",
+ "messages": {
+ "-1340279385": {
+ "message": "Remove listener=%s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
+ "-880817403": {
+ "message": "Task vanished taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
+ "-460572385": {
+ "message": "Task appeared taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
+ "-242812822": {
+ "message": "Add listener for modes=%s listener=%s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
+ "157713005": {
+ "message": "Task info changed taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
+ "980952660": {
+ "message": "Task root back pressed taskId=%d",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ }
+ },
+ "groups": {
+ "WM_SHELL_TASK_ORG": {
+ "tag": "WindowManagerShell"
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 1263748..ea9576a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -17,17 +17,20 @@
package com.android.wm.shell;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.WindowConfiguration;
+import android.content.Context;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TaskOrganizer;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.protolog.ShellProtoLogImpl;
+
import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.Arrays;
/**
* Unified task organizer for all components in the shell.
@@ -57,6 +60,8 @@
* Adds a listener for tasks in a specific windowing mode.
*/
public void addListener(TaskListener listener, int... windowingModes) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Add listener for modes=%s listener=%s",
+ Arrays.toString(windowingModes), listener);
for (int winMode : windowingModes) {
ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(winMode);
if (listeners == null) {
@@ -84,6 +89,7 @@
* Removes a registered listener.
*/
public void removeListener(TaskListener listener) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Remove listener=%s", listener);
for (int i = 0; i < mListenersByWindowingMode.size(); i++) {
mListenersByWindowingMode.valueAt(i).remove(listener);
}
@@ -91,6 +97,8 @@
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task appeared taskId=%d",
+ taskInfo.taskId);
mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, leash));
ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(
getWindowingMode(taskInfo));
@@ -103,6 +111,8 @@
@Override
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task info changed taskId=%d",
+ taskInfo.taskId);
Pair<RunningTaskInfo, SurfaceControl> data = mTasks.get(taskInfo.taskId);
int winMode = getWindowingMode(taskInfo);
int prevWinMode = getWindowingMode(data.first);
@@ -134,6 +144,8 @@
@Override
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task root back pressed taskId=%d",
+ taskInfo.taskId);
ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(
getWindowingMode(taskInfo));
if (listeners != null) {
@@ -145,6 +157,8 @@
@Override
public void onTaskVanished(RunningTaskInfo taskInfo) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task vanished taskId=%d",
+ taskInfo.taskId);
int prevWinMode = getWindowingMode(mTasks.get(taskInfo.taskId).first);
mTasks.remove(taskInfo.taskId);
ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(prevWinMode);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
new file mode 100644
index 0000000..ae09754
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -0,0 +1,92 @@
+/*
+ * 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.wm.shell.protolog;
+
+import com.android.internal.protolog.common.IProtoLogGroup;
+
+/**
+ * Defines logging groups for ProtoLog.
+ *
+ * This file is used by the ProtoLogTool to generate optimized logging code.
+ */
+public enum ShellProtoLogGroup implements IProtoLogGroup {
+ WM_SHELL_TASK_ORG(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM_SHELL),
+ TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest");
+
+ private final boolean mEnabled;
+ private volatile boolean mLogToProto;
+ private volatile boolean mLogToLogcat;
+ private final String mTag;
+
+ /**
+ * @param enabled set to false to exclude all log statements for this group from
+ * compilation,
+ * they will not be available in runtime.
+ * @param logToProto enable binary logging for the group
+ * @param logToLogcat enable text logging for the group
+ * @param tag name of the source of the logged message
+ */
+ ShellProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) {
+ this.mEnabled = enabled;
+ this.mLogToProto = logToProto;
+ this.mLogToLogcat = logToLogcat;
+ this.mTag = tag;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
+ @Override
+ public boolean isLogToProto() {
+ return mLogToProto;
+ }
+
+ @Override
+ public boolean isLogToLogcat() {
+ return mLogToLogcat;
+ }
+
+ @Override
+ public boolean isLogToAny() {
+ return mLogToLogcat || mLogToProto;
+ }
+
+ @Override
+ public String getTag() {
+ return mTag;
+ }
+
+ @Override
+ public void setLogToProto(boolean logToProto) {
+ this.mLogToProto = logToProto;
+ }
+
+ @Override
+ public void setLogToLogcat(boolean logToLogcat) {
+ this.mLogToLogcat = logToLogcat;
+ }
+
+ private static class Consts {
+ private static final String TAG_WM_SHELL = "WindowManagerShell";
+
+ private static final boolean ENABLE_DEBUG = true;
+ private static final boolean ENABLE_LOG_TO_PROTO_DEBUG = true;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java
new file mode 100644
index 0000000..6a925e7
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java
@@ -0,0 +1,138 @@
+/*
+ * 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.wm.shell.protolog;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.BaseProtoLogImpl;
+import com.android.internal.protolog.ProtoLogViewerConfigReader;
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.wm.shell.R;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import org.json.JSONException;
+
+
+/**
+ * A service for the ProtoLog logging system.
+ */
+public class ShellProtoLogImpl extends BaseProtoLogImpl {
+ private static final String TAG = "ProtoLogImpl";
+ private static final int BUFFER_CAPACITY = 1024 * 1024;
+ // TODO: Get the right path for the proto log file when we initialize the shell components
+ private static final String LOG_FILENAME = new File("wm_shell_log.pb").getAbsolutePath();
+
+ private static ShellProtoLogImpl sServiceInstance = null;
+
+ private final PrintWriter mSystemOutWriter;
+
+ static {
+ addLogGroupEnum(ShellProtoLogGroup.values());
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void d(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance()
+ .log(LogLevel.DEBUG, group, messageHash, paramsMask, messageString, args);
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void v(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance().log(LogLevel.VERBOSE, group, messageHash, paramsMask, messageString,
+ args);
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void i(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance().log(LogLevel.INFO, group, messageHash, paramsMask, messageString, args);
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void w(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance().log(LogLevel.WARN, group, messageHash, paramsMask, messageString, args);
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void e(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance()
+ .log(LogLevel.ERROR, group, messageHash, paramsMask, messageString, args);
+ }
+
+ /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
+ public static void wtf(IProtoLogGroup group, int messageHash, int paramsMask,
+ @Nullable String messageString,
+ Object... args) {
+ getSingleInstance().log(LogLevel.WTF, group, messageHash, paramsMask, messageString, args);
+ }
+
+ /** Returns true iff logging is enabled for the given {@code IProtoLogGroup}. */
+ public static boolean isEnabled(IProtoLogGroup group) {
+ return group.isLogToLogcat()
+ || (group.isLogToProto() && getSingleInstance().isProtoEnabled());
+ }
+
+ /**
+ * Returns the single instance of the ProtoLogImpl singleton class.
+ */
+ public static synchronized ShellProtoLogImpl getSingleInstance() {
+ if (sServiceInstance == null) {
+ sServiceInstance = new ShellProtoLogImpl();
+ }
+ return sServiceInstance;
+ }
+
+ public void startTextLogging(Context context, String... groups) {
+ try {
+ mViewerConfig.loadViewerConfig(
+ context.getResources().openRawResource(R.raw.wm_shell_protolog));
+ setLogging(true /* setTextLogging */, true, mSystemOutWriter, groups);
+ } catch (IOException e) {
+ Log.i(TAG, "Unable to load log definitions: IOException while reading "
+ + "wm_shell_protolog. " + e);
+ } catch (JSONException e) {
+ Log.i(TAG, "Unable to load log definitions: JSON parsing exception while reading "
+ + "wm_shell_protolog. " + e);
+ }
+ }
+
+ public void stopTextLogging(String... groups) {
+ setLogging(true /* setTextLogging */, false, mSystemOutWriter, groups);
+ }
+
+ private ShellProtoLogImpl() {
+ super(new File(LOG_FILENAME), null, BUFFER_CAPACITY,
+ new ProtoLogViewerConfigReader());
+ mSystemOutWriter = new PrintWriter(System.out, true);
+ }
+}
+
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 1803027..6fc702e 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -29,6 +29,8 @@
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -215,6 +217,7 @@
* @see #EXTRA_PROVIDER_ENABLED
* @see #isProviderEnabled(String)
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
/**
@@ -243,6 +246,7 @@
* @see #EXTRA_LOCATION_ENABLED
* @see #isLocationEnabled()
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
/**
diff --git a/media/packages/BluetoothMidiService/AndroidManifest.xml b/media/packages/BluetoothMidiService/AndroidManifest.xml
index b88bf2a..fc96fd9 100644
--- a/media/packages/BluetoothMidiService/AndroidManifest.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifest.xml
@@ -19,8 +19,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.android.bluetoothmidiservice"
- android:versionCode="1"
- android:versionName="R-initial"
>
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
diff --git a/media/packages/BluetoothMidiService/AndroidManifestBase.xml b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
index ebe62b0..bfb0546 100644
--- a/media/packages/BluetoothMidiService/AndroidManifestBase.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
@@ -18,8 +18,6 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.bluetoothmidiservice"
- android:versionCode="1"
- android:versionName="R-initial"
>
<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
<application
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index e0ebec6..e1b3151 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -11617,6 +11617,16 @@
field public int version;
}
+ public final class FileChecksum implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getKind();
+ method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException;
+ method @Nullable public String getSplitName();
+ method @NonNull public byte[] getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.FileChecksum> CREATOR;
+ }
+
public final class InstallSourceInfo implements android.os.Parcelable {
method public int describeContents();
method @Nullable public String getInitiatingPackageName();
@@ -11992,6 +12002,7 @@
method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public CharSequence getBackgroundPermissionOptionLabel();
method @Nullable public abstract android.content.pm.ChangedPackages getChangedPackages(@IntRange(from=0) int);
+ method public void getChecksums(@NonNull String, boolean, int, @Nullable java.util.List<java.security.cert.Certificate>, @NonNull android.content.IntentSender) throws java.security.cert.CertificateEncodingException, java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName);
method @NonNull public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
method @Nullable public abstract android.graphics.drawable.Drawable getDrawable(@NonNull String, @DrawableRes int, @Nullable android.content.pm.ApplicationInfo);
@@ -12082,6 +12093,7 @@
field public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; // 0x3
field public static final int COMPONENT_ENABLED_STATE_ENABLED = 1; // 0x1
field public static final int DONT_KILL_APP = 1; // 0x1
+ field public static final String EXTRA_CHECKSUMS = "android.content.pm.extra.CHECKSUMS";
field public static final String EXTRA_VERIFICATION_ID = "android.content.pm.extra.VERIFICATION_ID";
field public static final String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT";
field public static final String FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS = "android.software.activities_on_secondary_displays";
@@ -12236,6 +12248,8 @@
field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20
+ field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff
@@ -12245,9 +12259,16 @@
field public static final int SIGNATURE_SECOND_NOT_SIGNED = -2; // 0xfffffffe
field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc
field public static final int SYNCHRONOUS = 2; // 0x2
+ field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
+ field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
+ field public static final int WHOLE_MD5 = 2; // 0x2
+ field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1
+ field public static final int WHOLE_SHA1 = 4; // 0x4
+ field public static final int WHOLE_SHA256 = 8; // 0x8
+ field public static final int WHOLE_SHA512 = 16; // 0x10
}
public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index d1264df..7cce0f2 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -219,6 +219,7 @@
field public static final String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT";
field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
field public static final String SHUTDOWN = "android.permission.SHUTDOWN";
+ field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE";
field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
index 9039671..1a6fdfa 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
@@ -16,7 +16,6 @@
package com.android.systemui;
-import com.android.systemui.dagger.DependencyBinder;
import com.android.systemui.dagger.DependencyProvider;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.SysUISingleton;
@@ -32,7 +31,6 @@
@Subcomponent(modules = {
CarComponentBinder.class,
DependencyProvider.class,
- DependencyBinder.class,
PipModule.class,
SystemUIModule.class,
CarSystemUIModule.class,
diff --git a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java b/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
index fd6685f..6d31a8d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
@@ -22,8 +22,6 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.pip.phone.PipMenuActivity;
-import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
import com.android.systemui.wm.DisplaySystemBarsController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
@@ -43,12 +41,4 @@
return new DisplaySystemBarsController(context, wmService, displayController,
mainHandler, transactionPool);
}
-
- /** TODO(b/150319024): PipMenuActivity will move to a Window */
- @SysUISingleton
- @PipMenuActivityClass
- @Provides
- Class<?> providePipMenuActivityClass() {
- return PipMenuActivity.class;
- }
}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index f42bf19..11d1b0a 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -483,6 +483,13 @@
}
@Override
+ protected void onDocIdDeleted(String docId) {
+ Uri uri = DocumentsContract.buildDocumentUri(AUTHORITY, docId);
+ getContext().revokeUriPermission(uri, ~0);
+ }
+
+
+ @Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
synchronized (mRootsLock) {
diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_0.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_0.xml
new file mode 100644
index 0000000..16e9190
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_0.xml
@@ -0,0 +1,31 @@
+<!--
+ 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="25.50"
+ android:viewportHeight="25.50">
+ <group
+ android:translateX="0.77"
+ android:translateY="0.23" >
+ <path
+ android:pathData="M14,12h6.54l3.12,-3.89c0.39,-0.48 0.29,-1.19 -0.22,-1.54C21.67,5.36 17.55,3 12,3C6.44,3 2.33,5.36 0.56,6.57C0.05,6.92 -0.05,7.63 0.33,8.11L11.16,21.6c0.42,0.53 1.23,0.53 1.66,0L14,20.13V12z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M22.71,15.67l-1.83,1.83l1.83,1.83c0.38,0.38 0.38,1 0,1.38v0c-0.38,0.38 -1,0.39 -1.38,0l-1.83,-1.83l-1.83,1.83c-0.38,0.38 -1,0.38 -1.38,0l-0.01,-0.01c-0.38,-0.38 -0.38,-1 0,-1.38l1.83,-1.83l-1.82,-1.82c-0.38,-0.38 -0.38,-1 0,-1.38l0.01,-0.01c0.38,-0.38 1,-0.38 1.38,0l1.82,1.82l1.82,-1.82c0.38,-0.38 1,-0.38 1.38,0l0,0C23.09,14.67 23.09,15.29 22.71,15.67z"
+ android:fillColor="#FFFFFF"/>
+ </group>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_1.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_1.xml
new file mode 100644
index 0000000..4c338c9
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_1.xml
@@ -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.
+-->
+<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="@android:color/white"
+ android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2.01C7.25,2.01 2.97,4.09 0,7.4L7.582,16.625C7.582,16.627 7.58,16.629 7.58,16.631L11.99,22L12,22L13,20.789L13,17.641L13,13.119C12.68,13.039 12.34,13 12,13C10.601,13 9.351,13.64 8.531,14.639L2.699,7.539C5.269,5.279 8.58,4.01 12,4.01C15.42,4.01 18.731,5.279 21.301,7.539L16.811,13L19.4,13L24,7.4C21.03,4.09 16.75,2.01 12,2.01z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_2.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_2.xml
new file mode 100644
index 0000000..79037db
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_2.xml
@@ -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.
+-->
+<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="@android:color/white"
+ android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C7.25,2 2.97,4.081 0,7.391L12,22L13,20.779L13,17.631L13,13L16.801,13L18,13L19.391,13L24,7.391C21.03,4.081 16.75,2 12,2zM12,4C14.747,4 17.423,4.819 19.701,6.313C20.259,6.678 20.795,7.085 21.301,7.529L17.389,12.287C16.029,10.868 14.119,9.99 12,9.99C9.88,9.99 7.969,10.869 6.609,12.289L2.699,7.529C5.269,5.269 8.58,4 12,4z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_3.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_3.xml
new file mode 100644
index 0000000..21ad128
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_3.xml
@@ -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.
+-->
+<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="@android:color/white"
+ android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C7.25,2 2.97,4.081 0,7.391L3.301,11.41L12,22L13,20.779L13,17.631L13,13L16.801,13L19.391,13L20.699,11.41C20.699,11.409 20.698,11.409 20.697,11.408L24,7.391C21.03,4.081 16.75,2 12,2zM12,4C15.42,4 18.731,5.269 21.301,7.529L19.35,9.9C17.43,8.1 14.86,6.99 12,6.99C9.14,6.99 6.57,8.1 4.65,9.9C4.65,9.901 4.649,9.902 4.648,9.902L2.699,7.529C5.269,5.269 8.58,4 12,4z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_4.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_4.xml
new file mode 100644
index 0000000..2ec5ba3
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_4.xml
@@ -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.
+-->
+<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="@android:color/white"
+ android:pathData="M12,2C7.25,2 2.97,4.08 0,7.39L12,22l1,-1.22V13h6.39L24,7.39C21.03,4.08 16.75,2 12,2z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
+</vector>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index a43412e..b280806 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -49,11 +49,19 @@
private static String sSharedSystemSharedLibPackageName;
static final int[] WIFI_PIE = {
- com.android.internal.R.drawable.ic_wifi_signal_0,
- com.android.internal.R.drawable.ic_wifi_signal_1,
- com.android.internal.R.drawable.ic_wifi_signal_2,
- com.android.internal.R.drawable.ic_wifi_signal_3,
- com.android.internal.R.drawable.ic_wifi_signal_4
+ com.android.internal.R.drawable.ic_wifi_signal_0,
+ com.android.internal.R.drawable.ic_wifi_signal_1,
+ com.android.internal.R.drawable.ic_wifi_signal_2,
+ com.android.internal.R.drawable.ic_wifi_signal_3,
+ com.android.internal.R.drawable.ic_wifi_signal_4
+ };
+
+ static final int[] SHOW_X_WIFI_PIE = {
+ R.drawable.ic_show_x_wifi_signal_0,
+ R.drawable.ic_show_x_wifi_signal_1,
+ R.drawable.ic_show_x_wifi_signal_2,
+ R.drawable.ic_show_x_wifi_signal_3,
+ R.drawable.ic_show_x_wifi_signal_4
};
public static void updateLocationEnabled(Context context, boolean enabled, int userId,
@@ -353,10 +361,22 @@
* @throws IllegalArgumentException if an invalid RSSI level is given.
*/
public static int getWifiIconResource(int level) {
+ return getWifiIconResource(false /* showX */, level);
+ }
+
+ /**
+ * Returns the Wifi icon resource for a given RSSI level.
+ *
+ * @param showX True if a connected Wi-Fi network has the problem which should show Pie+x
+ * signal icon to users.
+ * @param level The number of bars to show (0-4)
+ * @throws IllegalArgumentException if an invalid RSSI level is given.
+ */
+ public static int getWifiIconResource(boolean showX, int level) {
if (level < 0 || level >= WIFI_PIE.length) {
throw new IllegalArgumentException("No Wifi icon found for level: " + level);
}
- return WIFI_PIE[level];
+ return showX ? SHOW_X_WIFI_PIE[level] : WIFI_PIE[level];
}
public static int getDefaultStorageManagerDaysToRetain(Resources resources) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
index a53bc9f..bba69f2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
@@ -35,6 +35,7 @@
import com.android.settingslib.R;
import com.android.settingslib.Utils;
import com.android.wifitrackerlib.WifiEntry;
+import com.android.wifitrackerlib.WifiEntry.ConnectedInfo;
/**
* Preference to display a WifiEntry in a wifi picker.
@@ -64,6 +65,7 @@
private final IconInjector mIconInjector;
private WifiEntry mWifiEntry;
private int mLevel = -1;
+ private boolean mShowX; // Shows the Wi-Fi signl icon of Pie+x when it's true.
private CharSequence mContentDescription;
private OnButtonClickListener mOnButtonClickListener;
@@ -136,9 +138,15 @@
public void refresh() {
setTitle(mWifiEntry.getTitle());
final int level = mWifiEntry.getLevel();
- if (level != mLevel) {
+ final ConnectedInfo connectedInfo = mWifiEntry.getConnectedInfo();
+ boolean showX = false;
+ if (connectedInfo != null) {
+ showX = !connectedInfo.isDefaultNetwork || !connectedInfo.isValidated;
+ }
+ if (level != mLevel || showX != mShowX) {
mLevel = level;
- updateIcon(mLevel);
+ mShowX = showX;
+ updateIcon(mShowX, mLevel);
notifyChanged();
}
@@ -184,13 +192,13 @@
}
- private void updateIcon(int level) {
+ private void updateIcon(boolean showX, int level) {
if (level == -1) {
setIcon(null);
return;
}
- final Drawable drawable = mIconInjector.getIcon(level);
+ final Drawable drawable = mIconInjector.getIcon(showX, level);
if (drawable != null) {
drawable.setTintList(Utils.getColorAttr(getContext(),
android.R.attr.colorControlNormal));
@@ -260,8 +268,8 @@
mContext = context;
}
- public Drawable getIcon(int level) {
- return mContext.getDrawable(Utils.getWifiIconResource(level));
+ public Drawable getIcon(boolean showX, int level) {
+ return mContext.getDrawable(Utils.getWifiIconResource(showX, level));
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
index 46e699d..40af7dc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
@@ -17,6 +17,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -29,6 +30,7 @@
import com.android.settingslib.R;
import com.android.wifitrackerlib.WifiEntry;
+import com.android.wifitrackerlib.WifiEntry.ConnectedInfo;
import org.junit.Before;
import org.junit.Test;
@@ -62,6 +64,17 @@
@Mock
private Drawable mMockDrawable4;
+ @Mock
+ private Drawable mMockShowXDrawable0;
+ @Mock
+ private Drawable mMockShowXDrawable1;
+ @Mock
+ private Drawable mMockShowXDrawable2;
+ @Mock
+ private Drawable mMockShowXDrawable3;
+ @Mock
+ private Drawable mMockShowXDrawable4;
+
private static final String MOCK_TITLE = "title";
private static final String MOCK_SUMMARY = "summary";
private static final String FAKE_URI_STRING = "fakeuri";
@@ -75,11 +88,22 @@
when(mMockWifiEntry.getTitle()).thenReturn(MOCK_TITLE);
when(mMockWifiEntry.getSummary(false /* concise */)).thenReturn(MOCK_SUMMARY);
- when(mMockIconInjector.getIcon(0)).thenReturn(mMockDrawable0);
- when(mMockIconInjector.getIcon(1)).thenReturn(mMockDrawable1);
- when(mMockIconInjector.getIcon(2)).thenReturn(mMockDrawable2);
- when(mMockIconInjector.getIcon(3)).thenReturn(mMockDrawable3);
- when(mMockIconInjector.getIcon(4)).thenReturn(mMockDrawable4);
+ when(mMockIconInjector.getIcon(false /* showX */, 0)).thenReturn(mMockDrawable0);
+ when(mMockIconInjector.getIcon(false /* showX */, 1)).thenReturn(mMockDrawable1);
+ when(mMockIconInjector.getIcon(false /* showX */, 2)).thenReturn(mMockDrawable2);
+ when(mMockIconInjector.getIcon(false /* showX */, 3)).thenReturn(mMockDrawable3);
+ when(mMockIconInjector.getIcon(false /* showX */, 4)).thenReturn(mMockDrawable4);
+
+ when(mMockIconInjector.getIcon(true /* showX */, 0))
+ .thenReturn(mMockShowXDrawable0);
+ when(mMockIconInjector.getIcon(true /* showX */, 1))
+ .thenReturn(mMockShowXDrawable1);
+ when(mMockIconInjector.getIcon(true /* showX */, 2))
+ .thenReturn(mMockShowXDrawable2);
+ when(mMockIconInjector.getIcon(true /* showX */, 3))
+ .thenReturn(mMockShowXDrawable3);
+ when(mMockIconInjector.getIcon(true /* showX */, 4))
+ .thenReturn(mMockShowXDrawable4);
}
@Test
@@ -155,6 +179,70 @@
}
@Test
+ public void levelChanged_notDefaultWifiRefresh_shouldUpdateLevelIcon() {
+ final List<Drawable> iconList = new ArrayList<>();
+ final ConnectedInfo mockConnectedInfo = mock(ConnectedInfo.class);
+ mockConnectedInfo.isDefaultNetwork = false;
+ when(mMockWifiEntry.getConnectedInfo()).thenReturn(mockConnectedInfo);
+ final WifiEntryPreference pref =
+ new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
+
+ when(mMockWifiEntry.getLevel()).thenReturn(0);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(1);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(2);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(3);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(4);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(-1);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+
+ assertThat(iconList).containsExactly(mMockShowXDrawable0, mMockShowXDrawable1,
+ mMockShowXDrawable2, mMockShowXDrawable3, mMockShowXDrawable4, null);
+ }
+
+ @Test
+ public void levelChanged_notValidatedWifiRefresh_shouldUpdateLevelIcon() {
+ final List<Drawable> iconList = new ArrayList<>();
+ final ConnectedInfo mockConnectedInfo = mock(ConnectedInfo.class);
+ mockConnectedInfo.isValidated = false;
+ when(mMockWifiEntry.getConnectedInfo()).thenReturn(mockConnectedInfo);
+ final WifiEntryPreference pref =
+ new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
+
+ when(mMockWifiEntry.getLevel()).thenReturn(0);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(1);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(2);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(3);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(4);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+ when(mMockWifiEntry.getLevel()).thenReturn(-1);
+ pref.refresh();
+ iconList.add(pref.getIcon());
+
+ assertThat(iconList).containsExactly(mMockShowXDrawable0, mMockShowXDrawable1,
+ mMockShowXDrawable2, mMockShowXDrawable3, mMockShowXDrawable4, null);
+ }
+
+ @Test
public void notNull_whenGetHelpUriString_shouldSetImageButtonVisible() {
when(mMockWifiEntry.getHelpUriString()).thenReturn(FAKE_URI_STRING);
final WifiEntryPreference pref =
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 2fbd9ba..0f2e25c 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -174,6 +174,9 @@
kotlincflags: ["-Xjvm-default=enable"],
dxflags: ["--multi-dex"],
- required: ["privapp_whitelist_com.android.systemui"],
+ required: [
+ "privapp_whitelist_com.android.systemui",
+ "checked-wm_shell_protolog.json",
+ ],
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index af008b9..7f4f580 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -530,20 +530,6 @@
androidprv:alwaysFocusable="true"
android:excludeFromRecents="true" />
- <activity
- android:name=".pip.phone.PipMenuActivity"
- android:permission="com.android.systemui.permission.SELF"
- android:theme="@style/PipPhoneOverlayControlTheme"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
- android:excludeFromRecents="true"
- android:exported="false"
- android:resizeableActivity="true"
- android:supportsPictureInPicture="true"
- android:stateNotNeeded="true"
- android:taskAffinity=""
- android:launchMode="singleTop"
- androidprv:alwaysFocusable="true" />
-
<!-- started from SliceProvider -->
<activity android:name=".SlicePermissionActivity"
android:theme="@style/Theme.SystemUI.Dialog.Alert"
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index df66bf5..6c06b0a 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -41,7 +41,12 @@
public <init>(android.content.Context);
}
+# Keep the wm shell lib
-keep class com.android.wm.shell.*
+# Keep the protolog group methods that are called by the generated code
+-keepclassmembers class com.android.wm.shell.protolog.ShellProtoLogGroup {
+ *;
+}
-keep class com.android.systemui.dagger.GlobalRootComponent { *; }
-keep class com.android.systemui.dagger.GlobalRootComponent$SysUIComponentImpl { *; }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
index 35a2392..2470b95 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
@@ -86,7 +86,10 @@
mLiveData.observeForever(mObserver);
}
mConfigurationController.addCallback(mConfigurationListener);
- mDumpManager.registerDumpable(TAG, KeyguardSliceViewController.this);
+ mDumpManager.registerDumpable(
+ TAG + "@" + Integer.toHexString(
+ KeyguardSliceViewController.this.hashCode()),
+ KeyguardSliceViewController.this);
}
@Override
@@ -230,5 +233,7 @@
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println(" mSlice: " + mSlice);
pw.println(" mClickActions: " + mClickActions);
+
+ mKeyguardStatusView.dump(fd, pw, args);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index d1149d3..f4c865e 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -21,7 +21,7 @@
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -38,7 +38,7 @@
*
* NOTE: Clients of this class should take care to pass in the correct user context when querying
* settings, otherwise you will always read/write for user 0 which is almost never what you want.
- * See {@link CurrentUserContextTracker} for a simple way to get the current context
+ * See {@link UserContextProvider} for a simple way to get the current context
*/
public final class Prefs {
private Prefs() {} // no instantation
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index f5c3649..941fd6f 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -38,6 +38,7 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
/**
@@ -83,11 +84,16 @@
public SystemUIFactory() {}
- private void init(Context context) {
+ private void init(Context context) throws ExecutionException, InterruptedException {
mRootComponent = buildGlobalRootComponent(context);
+ // Stand up WMComponent
mWMComponent = mRootComponent.getWMComponentBuilder().build();
- // TODO: use WMComponent to pass APIs into the SysUIComponent.
- mSysUIComponent = mRootComponent.getSysUIComponent().build();
+
+ // And finally, retrieve whatever SysUI needs from WMShell and build SysUI.
+ // TODO: StubAPIClass is just a placeholder.
+ mSysUIComponent = mRootComponent.getSysUIComponent()
+ .setStubAPIClass(mWMComponent.createStubAPIClass())
+ .build();
// Every other part of our codebase currently relies on Dependency, so we
// really need to ensure the Dependency gets initialized early on.
@@ -101,10 +107,15 @@
.build();
}
+
public GlobalRootComponent getRootComponent() {
return mRootComponent;
}
+ public WMComponent getWMComponent() {
+ return mWMComponent;
+ }
+
public SysUIComponent getSysUIComponent() {
return mSysUIComponent;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java b/packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.java
similarity index 61%
copy from packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
copy to packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.java
index 114c30e..d4cc3f3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.java
@@ -14,17 +14,19 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone.dagger;
+package com.android.systemui.appops.dagger;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.appops.AppOpsControllerImpl;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
+import dagger.Binds;
+import dagger.Module;
-import javax.inject.Qualifier;
+/** Dagger Module for code in the appops package. */
+@Module
+public interface AppOpsModule {
+ /** */
+ @Binds
+ AppOpsController provideAppOpsController(AppOpsControllerImpl controllerImpl);
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface PipMenuActivityClass {
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
deleted file mode 100644
index e2a6d6c..0000000
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * 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 com.android.systemui.ActivityStarterDelegate;
-import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.appops.AppOpsControllerImpl;
-import com.android.systemui.classifier.FalsingManagerProxy;
-import com.android.systemui.controls.dagger.ControlsModule;
-import com.android.systemui.globalactions.GlobalActionsComponent;
-import com.android.systemui.globalactions.GlobalActionsImpl;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.GlobalActions;
-import com.android.systemui.plugins.VolumeDialogController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.power.PowerNotificationWarnings;
-import com.android.systemui.power.PowerUI;
-import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.StatusBarStateControllerImpl;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
-import com.android.systemui.statusbar.phone.ManagedProfileController;
-import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
-import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.CastControllerImpl;
-import com.android.systemui.statusbar.policy.ExtensionController;
-import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
-import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.HotspotControllerImpl;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.KeyguardStateControllerImpl;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.LocationControllerImpl;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
-import com.android.systemui.statusbar.policy.SecurityController;
-import com.android.systemui.statusbar.policy.SecurityControllerImpl;
-import com.android.systemui.statusbar.policy.SensorPrivacyController;
-import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerServiceImpl;
-import com.android.systemui.util.RingerModeTracker;
-import com.android.systemui.util.RingerModeTrackerImpl;
-import com.android.systemui.volume.VolumeComponent;
-import com.android.systemui.volume.VolumeDialogComponent;
-import com.android.systemui.volume.VolumeDialogControllerImpl;
-
-import dagger.Binds;
-import dagger.Module;
-
-/**
- * Maps interfaces to implementations for use with Dagger.
- */
-@Module(includes = {ControlsModule.class})
-public abstract class DependencyBinder {
-
- /**
- */
- @Binds
- public abstract ActivityStarter provideActivityStarter(ActivityStarterDelegate delegate);
-
- /**
- */
- @Binds
- public abstract BluetoothController provideBluetoothController(
- BluetoothControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract GlobalActions provideGlobalActions(GlobalActionsImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract GlobalActions.GlobalActionsManager provideGlobalActionsManager(
- GlobalActionsComponent controllerImpl);
-
- /**
- */
- @Binds
- public abstract LocationController provideLocationController(
- LocationControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract RotationLockController provideRotationLockController(
- RotationLockControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract NetworkController provideNetworkController(
- NetworkControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract ZenModeController provideZenModeController(
- ZenModeControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract HotspotController provideHotspotController(
- HotspotControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract AppOpsController provideAppOpsController(
- AppOpsControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract NotificationRemoteInputManager.Callback provideNotificationRemoteInputManager(
- StatusBarRemoteInputCallback callbackImpl);
-
- /**
- */
- @Binds
- public abstract CastController provideCastController(CastControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract FlashlightController provideFlashlightController(
- FlashlightControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract KeyguardStateController provideKeyguardMonitor(
- KeyguardStateControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract UserInfoController provideUserInfoContrller(
- UserInfoControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract ManagedProfileController provideManagedProfileController(
- ManagedProfileControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract NextAlarmController provideNextAlarmController(
- NextAlarmControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract SecurityController provideSecurityController(
- SecurityControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract TunerService provideTunerService(TunerServiceImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract DarkIconDispatcher provideDarkIconDispatcher(
- DarkIconDispatcherImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract StatusBarStateController provideStatusBarStateController(
- StatusBarStateControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract SysuiStatusBarStateController providesSysuiStatusBarStateController(
- StatusBarStateControllerImpl statusBarStateControllerImpl);
-
- /**
- */
- @Binds
- public abstract StatusBarIconController provideStatusBarIconController(
- StatusBarIconControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract ExtensionController provideExtensionController(
- ExtensionControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract VolumeDialogController provideVolumeDialogController(
- VolumeDialogControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract PowerUI.WarningsUI provideWarningsUi(PowerNotificationWarnings controllerImpl);
-
- /**
- */
- @Binds
- public abstract SensorPrivacyController provideSensorPrivacyControllerImpl(
- SensorPrivacyControllerImpl controllerImpl);
-
- /**
- */
- @Binds
- public abstract QSHost provideQsHost(QSTileHost controllerImpl);
-
- /**
- */
- @Binds
- public abstract FalsingManager provideFalsingManager(FalsingManagerProxy falsingManagerImpl);
-
- /**
- */
- @Binds
- public abstract VolumeComponent provideVolumeComponent(
- VolumeDialogComponent volumeDialogComponent);
-
- /**
- */
- @Binds
- public abstract RingerModeTracker provideRingerModeTracker(
- RingerModeTrackerImpl ringerModeTrackerImpl);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index fd4a409..c5dc8cc 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -16,6 +16,8 @@
package com.android.systemui.dagger;
+import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
+
import dagger.Module;
/**
@@ -33,6 +35,8 @@
*
* Please use discretion when adding things to the global scope.
*/
-@Module(includes = {FrameworkServicesModule.class})
+@Module(includes = {
+ FrameworkServicesModule.class,
+ GlobalConcurrencyModule.class})
public class GlobalModule {
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
index 36fd337..00fdf55 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
@@ -18,6 +18,8 @@
import android.content.Context;
+import com.android.systemui.util.concurrency.ThreadFactory;
+
import javax.inject.Singleton;
import dagger.BindsInstance;
@@ -53,4 +55,9 @@
* Builder for a SysuiComponent.
*/
SysUIComponent.Builder getSysUIComponent();
+
+ /**
+ * Build a {@link ThreadFactory}.
+ */
+ ThreadFactory createThreadFactory();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java b/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java
new file mode 100644
index 0000000..406981d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java
@@ -0,0 +1,74 @@
+/*
+ * 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 com.android.systemui.ActivityStarterDelegate;
+import com.android.systemui.classifier.FalsingManagerProxy;
+import com.android.systemui.globalactions.GlobalActionsComponent;
+import com.android.systemui.globalactions.GlobalActionsImpl;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.GlobalActions;
+import com.android.systemui.plugins.VolumeDialogController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
+import com.android.systemui.volume.VolumeDialogControllerImpl;
+
+import dagger.Binds;
+import dagger.Module;
+
+/**
+ * Module for binding Plugin implementations.
+ *
+ * TODO(b/166258224): Many of these should be moved closer to their implementations.
+ */
+@Module
+public interface PluginModule {
+
+ /** */
+ @Binds
+ ActivityStarter provideActivityStarter(ActivityStarterDelegate delegate);
+
+ /** */
+ @Binds
+ DarkIconDispatcher provideDarkIconDispatcher(DarkIconDispatcherImpl controllerImpl);
+
+ /** */
+ @Binds
+ FalsingManager provideFalsingManager(FalsingManagerProxy falsingManagerImpl);
+
+ /** */
+ @Binds
+ GlobalActions provideGlobalActions(GlobalActionsImpl controllerImpl);
+
+ /** */
+ @Binds
+ GlobalActions.GlobalActionsManager provideGlobalActionsManager(
+ GlobalActionsComponent controllerImpl);
+
+ /** */
+ @Binds
+ StatusBarStateController provideStatusBarStateController(
+ StatusBarStateControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ VolumeDialogController provideVolumeDialogController(VolumeDialogControllerImpl controllerImpl);
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index e4e3d7a..2622593 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -26,6 +26,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.InjectionInflationController;
+import dagger.BindsInstance;
import dagger.Subcomponent;
/**
@@ -35,7 +36,6 @@
@Subcomponent(modules = {
DefaultComponentBinder.class,
DependencyProvider.class,
- DependencyBinder.class,
PipModule.class,
SystemUIBinder.class,
SystemUIModule.class,
@@ -47,6 +47,9 @@
*/
@Subcomponent.Builder
interface Builder {
+ @BindsInstance
+ Builder setStubAPIClass(WMComponent.StubAPIClass stubAPIClass);
+
SysUIComponent build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index e985e3d..99a3a91 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -18,12 +18,15 @@
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
+import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
+import com.android.systemui.controls.dagger.ControlsModule;
import com.android.systemui.demomode.dagger.DemoModeModule;
import com.android.systemui.doze.dagger.DozeComponent;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
+import com.android.systemui.power.dagger.PowerModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
@@ -37,11 +40,15 @@
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.util.concurrency.ConcurrencyModule;
+import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
+import com.android.systemui.tuner.dagger.TunerModule;
+import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
+import com.android.systemui.util.dagger.UtilModule;
import com.android.systemui.util.sensors.SensorModule;
import com.android.systemui.util.settings.SettingsUtilModule;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.util.time.SystemClockImpl;
+import com.android.systemui.volume.dagger.VolumeModule;
import dagger.Binds;
import dagger.BindsOptionalOf;
@@ -53,15 +60,23 @@
* implementation.
*/
@Module(includes = {
+ AppOpsModule.class,
AssistModule.class,
- ConcurrencyModule.class,
+ ControlsModule.class,
DemoModeModule.class,
LogModule.class,
PeopleHubModule.class,
+ PowerModule.class,
+ PluginModule.class,
ScreenshotModule.class,
SensorModule.class,
SettingsModule.class,
- SettingsUtilModule.class
+ SettingsUtilModule.class,
+ StatusBarPolicyModule.class,
+ SysUIConcurrencyModule.class,
+ TunerModule.class,
+ UtilModule.class,
+ VolumeModule.class
},
subcomponents = {StatusBarComponent.class,
NotificationRowComponent.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 929b61a..ad90eff 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -16,6 +16,8 @@
package com.android.systemui.dagger;
+import javax.inject.Inject;
+
import dagger.Subcomponent;
/**
@@ -32,4 +34,19 @@
interface Builder {
WMComponent build();
}
+
+
+ /**
+ * Example class used for passing an API to SysUI from WMShell.
+ *
+ * TODO: Remove this once real WM classes are ready to go.
+ **/
+ @WMSingleton
+ class StubAPIClass {
+ @Inject
+ StubAPIClass() {}
+ }
+
+ /** Create a StubAPIClass. */
+ StubAPIClass createStubAPIClass();
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index d213ac1..3e64749 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -130,7 +130,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -252,7 +252,7 @@
private final RingerModeTracker mRingerModeTracker;
private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms
private Handler mMainHandler;
- private CurrentUserContextTracker mCurrentUserContextTracker;
+ private UserContextProvider mUserContextProvider;
@VisibleForTesting
boolean mShowLockScreenCardsAndControls = false;
@@ -313,7 +313,7 @@
UiEventLogger uiEventLogger,
RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler,
ControlsComponent controlsComponent,
- CurrentUserContextTracker currentUserContextTracker) {
+ UserContextProvider userContextProvider) {
mContext = context;
mWindowManagerFuncs = windowManagerFuncs;
mAudioManager = audioManager;
@@ -342,7 +342,7 @@
mControlsControllerOptional = controlsComponent.getControlsController();
mSysUiState = sysUiState;
mMainHandler = handler;
- mCurrentUserContextTracker = currentUserContextTracker;
+ mUserContextProvider = userContextProvider;
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -436,7 +436,7 @@
String[] preferredControlsPackages = mContext.getResources()
.getStringArray(com.android.systemui.R.array.config_controlsPreferredPackages);
- SharedPreferences prefs = mCurrentUserContextTracker.getCurrentUserContext()
+ SharedPreferences prefs = mUserContextProvider.getUserContext()
.getSharedPreferences(PREFS_CONTROLS_FILE, Context.MODE_PRIVATE);
Set<String> seededPackages = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED,
Collections.emptySet());
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index a003d83..e5a9ac1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -172,7 +172,6 @@
// 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 {
addOrUpdatePlayer(key, oldKey, data)
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index aec3543..c7e7817 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -662,7 +662,7 @@
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
mOrientationParams.setTitle("SecondaryHomeHandle" + mContext.getDisplayId());
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
index 0354c72..8ef9b09 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
@@ -158,7 +158,9 @@
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
mDisplaySize.x, mTutorialAreaHeight, 0, 0,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
lp.gravity = Gravity.TOP | Gravity.LEFT;
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 7421ec1..c956702 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -49,6 +49,9 @@
import android.util.Log;
import android.util.Size;
import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.WindowManager;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -57,6 +60,7 @@
import com.android.internal.os.SomeArgs;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.pip.phone.PipMenuActivityController;
import com.android.systemui.pip.phone.PipUpdateThread;
import com.android.systemui.stackdivider.SplitScreen;
import com.android.wm.shell.R;
@@ -95,6 +99,7 @@
private static final int MSG_FINISH_RESIZE = 4;
private static final int MSG_RESIZE_USER = 5;
+ private final Context mContext;
private final Handler mMainHandler;
private final Handler mUpdateHandler;
private final PipBoundsHandler mPipBoundsHandler;
@@ -107,6 +112,8 @@
private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
private final Optional<SplitScreen> mSplitScreenOptional;
protected final ShellTaskOrganizer mTaskOrganizer;
+ private SurfaceControlViewHost mPipViewHost;
+ private SurfaceControl mPipMenuSurface;
// These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
@@ -212,6 +219,7 @@
@NonNull DisplayController displayController,
@NonNull PipUiEventLogger pipUiEventLogger,
@NonNull ShellTaskOrganizer shellTaskOrganizer) {
+ mContext = context;
mMainHandler = new Handler(Looper.getMainLooper());
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
mPipBoundsHandler = boundsHandler;
@@ -504,6 +512,45 @@
}
/**
+ * Setup the ViewHost and attach the provided menu view to the ViewHost.
+ */
+ public void attachPipMenuViewHost(View menuView, WindowManager.LayoutParams lp) {
+ if (mPipMenuSurface != null) {
+ Log.e(TAG, "PIP Menu View already created and attached.");
+ return;
+ }
+
+ if (Looper.getMainLooper() != Looper.myLooper()) {
+ throw new RuntimeException("PipMenuView needs to be attached on the main thread.");
+ }
+
+ mPipViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(),
+ (android.os.Binder) null);
+ mPipMenuSurface = mPipViewHost.getSurfacePackage().getSurfaceControl();
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ transaction.reparent(mPipMenuSurface, mLeash);
+ transaction.show(mPipMenuSurface);
+ transaction.setRelativeLayer(mPipMenuSurface, mLeash, 1);
+ transaction.apply();
+ mPipViewHost.setView(menuView, lp);
+ }
+
+
+ /**
+ * Releases the PIP Menu's View host, remove it from PIP task surface.
+ */
+ public void detachPipMenuViewHost() {
+ if (mPipMenuSurface != null) {
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ transaction.remove(mPipMenuSurface);
+ transaction.apply();
+ mPipMenuSurface = null;
+ mPipViewHost = null;
+ }
+ }
+
+
+ /**
* Note that dismissing PiP is now originated from SystemUI, see {@link #exitPip(int)}.
* Meanwhile this callback is invoked whenever the task is removed. For instance:
* - as a result of removeStacksInWindowingModes from WM
@@ -838,6 +885,12 @@
WindowContainerTransaction wct = new WindowContainerTransaction();
prepareFinishResizeTransaction(destinationBounds, direction, tx, wct);
applyFinishBoundsResize(wct, direction);
+ runOnMainHandler(() -> {
+ if (mPipViewHost != null) {
+ mPipViewHost.relayout(PipMenuActivityController.getPipMenuLayoutParams(
+ destinationBounds.width(), destinationBounds.height()));
+ }
+ });
}
private void prepareFinishResizeTransaction(Rect destinationBounds,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index d8864ec..5ef5b90 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -49,7 +49,6 @@
import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
@@ -267,7 +266,6 @@
@Inject
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
- @PipMenuActivityClass Class<?> pipMenuActivityClass,
ConfigurationController configController,
DeviceConfigProxy deviceConfig,
DisplayController displayController,
@@ -296,8 +294,8 @@
mPipTaskOrganizer.registerPipTransitionCallback(this);
mInputConsumerController = InputConsumerController.getPipInputConsumer();
mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
- mMenuController = new PipMenuActivityController(context, pipMenuActivityClass,
- mMediaController, mInputConsumerController);
+ mMenuController = new PipMenuActivityController(context,
+ mMediaController, mInputConsumerController, mPipTaskOrganizer);
mTouchHandler = new PipTouchHandler(context, mActivityManager,
mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
floatingContentCoordinator, deviceConfig, sysUiState, pipUiEventLogger);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
deleted file mode 100644
index 1b1b2de..0000000
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ /dev/null
@@ -1,730 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.pip.phone;
-
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.provider.Settings.ACTION_PICTURE_IN_PICTURE_SETTINGS;
-import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS;
-import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
-
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ACTIONS;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ALLOW_TIMEOUT;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_DISMISS_FRACTION;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MENU_STATE;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_SHOW_MENU_WITH_DELAY;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_SHOW_RESIZE_HANDLE;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_STACK_BOUNDS;
-import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_WILL_RESIZE_MENU;
-import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
-import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
-import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.PendingIntent.CanceledException;
-import android.app.RemoteAction;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ParceledListSlice;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.Pair;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager.LayoutParams;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.FrameLayout;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-
-import com.android.systemui.Interpolators;
-import com.android.wm.shell.R;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Translucent activity that gets started on top of a task in PIP to allow the user to control it.
- * TODO(b/150319024): PipMenuActivity will move to a Window
- */
-public class PipMenuActivity extends Activity {
-
- private static final String TAG = "PipMenuActivity";
-
- private static final int MESSAGE_INVALID_TYPE = -1;
-
- public static final int MESSAGE_SHOW_MENU = 1;
- public static final int MESSAGE_POKE_MENU = 2;
- public static final int MESSAGE_HIDE_MENU = 3;
- public static final int MESSAGE_UPDATE_ACTIONS = 4;
- public static final int MESSAGE_UPDATE_DISMISS_FRACTION = 5;
- public static final int MESSAGE_ANIMATION_ENDED = 6;
- public static final int MESSAGE_POINTER_EVENT = 7;
- public static final int MESSAGE_MENU_EXPANDED = 8;
- public static final int MESSAGE_FADE_OUT_MENU = 9;
- public static final int MESSAGE_UPDATE_MENU_LAYOUT = 10;
-
- private static final int INITIAL_DISMISS_DELAY = 3500;
- private static final int POST_INTERACTION_DISMISS_DELAY = 2000;
- private static final long MENU_FADE_DURATION = 125;
- private static final long MENU_SLOW_FADE_DURATION = 175;
- private static final long MENU_SHOW_ON_EXPAND_START_DELAY = 30;
-
- private static final float MENU_BACKGROUND_ALPHA = 0.3f;
- private static final float DISMISS_BACKGROUND_ALPHA = 0.6f;
-
- private static final float DISABLED_ACTION_ALPHA = 0.54f;
-
- private static final boolean ENABLE_RESIZE_HANDLE = false;
-
- private int mMenuState;
- private boolean mResize = true;
- private boolean mAllowMenuTimeout = true;
- private boolean mAllowTouches = true;
-
- private final List<RemoteAction> mActions = new ArrayList<>();
-
- private AccessibilityManager mAccessibilityManager;
- private Drawable mBackgroundDrawable;
- private View mMenuContainer;
- private LinearLayout mActionsGroup;
- private int mBetweenActionPaddingLand;
-
- private AnimatorSet mMenuContainerAnimator;
-
- private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
- new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final float alpha = (float) animation.getAnimatedValue();
- mBackgroundDrawable.setAlpha((int) (MENU_BACKGROUND_ALPHA*alpha*255));
- }
- };
-
- private Handler mHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_SHOW_MENU: {
- final Bundle data = (Bundle) msg.obj;
- showMenu(data.getInt(EXTRA_MENU_STATE),
- data.getParcelable(EXTRA_STACK_BOUNDS),
- data.getBoolean(EXTRA_ALLOW_TIMEOUT),
- data.getBoolean(EXTRA_WILL_RESIZE_MENU),
- data.getBoolean(EXTRA_SHOW_MENU_WITH_DELAY),
- data.getBoolean(EXTRA_SHOW_RESIZE_HANDLE));
- break;
- }
- case MESSAGE_POKE_MENU:
- cancelDelayedFinish();
- break;
- case MESSAGE_HIDE_MENU:
- hideMenu((Runnable) msg.obj);
- break;
- case MESSAGE_UPDATE_ACTIONS: {
- final Bundle data = (Bundle) msg.obj;
- final ParceledListSlice<RemoteAction> actions = data.getParcelable(
- EXTRA_ACTIONS);
- setActions(data.getParcelable(EXTRA_STACK_BOUNDS), actions != null
- ? actions.getList() : Collections.emptyList());
- break;
- }
- case MESSAGE_UPDATE_DISMISS_FRACTION: {
- final Bundle data = (Bundle) msg.obj;
- updateDismissFraction(data.getFloat(EXTRA_DISMISS_FRACTION));
- break;
- }
- case MESSAGE_ANIMATION_ENDED: {
- mAllowTouches = true;
- break;
- }
- case MESSAGE_POINTER_EVENT: {
- final MotionEvent ev = (MotionEvent) msg.obj;
- dispatchPointerEvent(ev);
- break;
- }
- case MESSAGE_MENU_EXPANDED : {
- if (mMenuContainerAnimator == null) {
- return;
- }
- mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
- mMenuContainerAnimator.start();
- break;
- }
- case MESSAGE_FADE_OUT_MENU: {
- fadeOutMenu();
- break;
- }
- case MESSAGE_UPDATE_MENU_LAYOUT: {
- if (mPipMenuIconsAlgorithm == null) {
- return;
- }
- final Rect bounds = (Rect) msg.obj;
- mPipMenuIconsAlgorithm.onBoundsChanged(bounds);
- break;
- }
- }
- }
- };
- private Messenger mToControllerMessenger;
- private Messenger mMessenger = new Messenger(mHandler);
-
- private final Runnable mFinishRunnable = this::hideMenu;
-
- protected View mViewRoot;
- protected View mSettingsButton;
- protected View mDismissButton;
- protected View mResizeHandle;
- protected View mTopEndContainer;
- protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- // Set the flags to allow us to watch for outside touches and also hide the menu and start
- // manipulating the PIP in the same touch gesture
- getWindow().addFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
-
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.pip_menu_activity);
-
- mAccessibilityManager = getSystemService(AccessibilityManager.class);
- mBackgroundDrawable = new ColorDrawable(Color.BLACK);
- mBackgroundDrawable.setAlpha(0);
- mViewRoot = findViewById(R.id.background);
- mViewRoot.setBackground(mBackgroundDrawable);
- mMenuContainer = findViewById(R.id.menu_container);
- mMenuContainer.setAlpha(0);
- mTopEndContainer = findViewById(R.id.top_end_container);
- mSettingsButton = findViewById(R.id.settings);
- mSettingsButton.setAlpha(0);
- mSettingsButton.setOnClickListener((v) -> {
- if (v.getAlpha() != 0) {
- showSettings();
- }
- });
- mDismissButton = findViewById(R.id.dismiss);
- mDismissButton.setAlpha(0);
- mDismissButton.setOnClickListener(v -> dismissPip());
- findViewById(R.id.expand_button).setOnClickListener(v -> {
- if (mMenuContainer.getAlpha() != 0) {
- expandPip();
- }
- });
- mResizeHandle = findViewById(R.id.resize_handle);
- mResizeHandle.setAlpha(0);
- mActionsGroup = findViewById(R.id.actions_group);
- mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
- R.dimen.pip_between_action_padding_land);
- mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(this.getApplicationContext());
- mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
- mResizeHandle, mSettingsButton, mDismissButton);
- updateFromIntent(getIntent());
- setTitle(R.string.pip_menu_title);
- setDisablePreviewScreenshots(true);
-
- // Hide without an animation.
- getWindow().setExitTransition(null);
-
- initAccessibility();
- }
-
- private void initAccessibility() {
- getWindow().getDecorView().setAccessibilityDelegate(new View.AccessibilityDelegate() {
- @Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- String label = getResources().getString(R.string.pip_menu_title);
- info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, label));
- }
-
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- if (action == ACTION_CLICK && mMenuState == MENU_STATE_CLOSE) {
- Message m = Message.obtain();
- m.what = PipMenuActivityController.MESSAGE_SHOW_MENU;
- sendMessage(m, "Could not notify controller to show PIP menu");
- }
- return super.performAccessibilityAction(host, action, args);
- }
- });
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
- hideMenu();
- return true;
- }
- return super.onKeyUp(keyCode, event);
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- updateFromIntent(intent);
- }
-
- @Override
- public void onUserInteraction() {
- if (mAllowMenuTimeout) {
- repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
- }
- }
-
- @Override
- protected void onUserLeaveHint() {
- super.onUserLeaveHint();
-
- // If another task is starting on top of the menu, then hide and finish it so that it can be
- // recreated on the top next time it starts
- hideMenu();
- }
-
- @Override
- public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
- super.onTopResumedActivityChanged(isTopResumedActivity);
- if (!isTopResumedActivity && mMenuState != MENU_STATE_NONE) {
- hideMenu();
- }
- }
-
- @Override
- protected void onStop() {
- super.onStop();
-
- // In cases such as device lock, hide and finish it so that it can be recreated on the top
- // next time it starts, see also {@link #onUserLeaveHint}
- hideMenu();
- cancelDelayedFinish();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
- // Fallback, if we are destroyed for any other reason (like when the task is being reset),
- // also reset the callback.
- notifyActivityCallback(null);
- }
-
- @Override
- public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
- if (!isInPictureInPictureMode) {
- finish();
- }
- }
-
- /**
- * Dispatch a pointer event from {@link PipTouchHandler}.
- */
- private void dispatchPointerEvent(MotionEvent event) {
- if (event.isTouchEvent()) {
- dispatchTouchEvent(event);
- } else {
- dispatchGenericMotionEvent(event);
- }
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (!mAllowTouches) {
- return false;
- }
-
- // On the first action outside the window, hide the menu
- switch (ev.getAction()) {
- case MotionEvent.ACTION_OUTSIDE:
- hideMenu();
- return true;
- }
- return super.dispatchTouchEvent(ev);
- }
-
- @Override
- public void finish() {
- notifyActivityCallback(null);
- super.finish();
- }
-
- @Override
- public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
- // Do nothing
- }
-
- private void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
- boolean resizeMenuOnShow, boolean withDelay, boolean showResizeHandle) {
- mAllowMenuTimeout = allowMenuTimeout;
- if (mMenuState != menuState) {
- // Disallow touches if the menu needs to resize while showing, and we are transitioning
- // to/from a full menu state.
- boolean disallowTouchesUntilAnimationEnd = resizeMenuOnShow &&
- (mMenuState == MENU_STATE_FULL || menuState == MENU_STATE_FULL);
- mAllowTouches = !disallowTouchesUntilAnimationEnd;
- cancelDelayedFinish();
- updateActionViews(stackBounds);
- if (mMenuContainerAnimator != null) {
- mMenuContainerAnimator.cancel();
- }
- mMenuContainerAnimator = new AnimatorSet();
- ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
- mMenuContainer.getAlpha(), 1f);
- menuAnim.addUpdateListener(mMenuBgUpdateListener);
- ObjectAnimator settingsAnim = ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA,
- mSettingsButton.getAlpha(), 1f);
- ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
- mDismissButton.getAlpha(), 1f);
- ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
- mResizeHandle.getAlpha(),
- ENABLE_RESIZE_HANDLE && menuState == MENU_STATE_CLOSE && showResizeHandle
- ? 1f : 0f);
- if (menuState == MENU_STATE_FULL) {
- mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
- resizeAnim);
- } else {
- mMenuContainerAnimator.playTogether(dismissAnim, resizeAnim);
- }
- mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
- mMenuContainerAnimator.setDuration(menuState == MENU_STATE_CLOSE
- ? MENU_FADE_DURATION
- : MENU_SLOW_FADE_DURATION);
- if (allowMenuTimeout) {
- mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- repostDelayedFinish(INITIAL_DISMISS_DELAY);
- }
- });
- }
- if (withDelay) {
- // starts the menu container animation after window expansion is completed
- notifyMenuStateChange(menuState, resizeMenuOnShow, MESSAGE_MENU_EXPANDED);
- } else {
- notifyMenuStateChange(menuState, resizeMenuOnShow, MESSAGE_INVALID_TYPE);
- mMenuContainerAnimator.start();
- }
- } else {
- // If we are already visible, then just start the delayed dismiss and unregister any
- // existing input consumers from the previous drag
- if (allowMenuTimeout) {
- repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
- }
- }
- }
-
- /**
- * Different from {@link #hideMenu()}, this function does not try to finish this menu activity
- * and instead, it fades out the controls by setting the alpha to 0 directly without menu
- * visibility callbacks invoked.
- */
- private void fadeOutMenu() {
- mMenuContainer.setAlpha(0f);
- mSettingsButton.setAlpha(0f);
- mDismissButton.setAlpha(0f);
- mResizeHandle.setAlpha(0f);
- }
-
- private void hideMenu() {
- hideMenu(null);
- }
-
- private void hideMenu(Runnable animationEndCallback) {
- hideMenu(animationEndCallback, true /* notifyMenuVisibility */, false /* isDismissing */,
- true /* animate */);
- }
-
- private void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility,
- boolean isDismissing, boolean animate) {
- if (mMenuState != MENU_STATE_NONE) {
- cancelDelayedFinish();
- if (notifyMenuVisibility) {
- notifyMenuStateChange(MENU_STATE_NONE, mResize, MESSAGE_INVALID_TYPE);
- }
- mMenuContainerAnimator = new AnimatorSet();
- ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
- mMenuContainer.getAlpha(), 0f);
- menuAnim.addUpdateListener(mMenuBgUpdateListener);
- ObjectAnimator settingsAnim = ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA,
- mSettingsButton.getAlpha(), 0f);
- ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
- mDismissButton.getAlpha(), 0f);
- ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
- mResizeHandle.getAlpha(), 0f);
- mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim, resizeAnim);
- mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
- mMenuContainerAnimator.setDuration(animate ? MENU_FADE_DURATION : 0);
- mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (animationFinishedRunnable != null) {
- animationFinishedRunnable.run();
- }
-
- if (!isDismissing) {
- // If we are dismissing the PiP, then don't try to pre-emptively finish the
- // menu activity
- finish();
- }
- }
- });
- mMenuContainerAnimator.start();
- } else {
- // If the menu is not visible, just finish now
- finish();
- }
- }
-
- private void updateFromIntent(Intent intent) {
- mToControllerMessenger = intent.getParcelableExtra(EXTRA_CONTROLLER_MESSENGER);
- if (mToControllerMessenger == null) {
- Log.w(TAG, "Controller messenger is null. Stopping.");
- finish();
- return;
- }
- notifyActivityCallback(mMessenger);
-
- ParceledListSlice<RemoteAction> actions = intent.getParcelableExtra(EXTRA_ACTIONS);
- if (actions != null) {
- mActions.clear();
- mActions.addAll(actions.getList());
- }
-
- final int menuState = intent.getIntExtra(EXTRA_MENU_STATE, MENU_STATE_NONE);
- if (menuState != MENU_STATE_NONE) {
- Rect stackBounds = intent.getParcelableExtra(EXTRA_STACK_BOUNDS);
- boolean allowMenuTimeout = intent.getBooleanExtra(EXTRA_ALLOW_TIMEOUT, true);
- boolean willResizeMenu = intent.getBooleanExtra(EXTRA_WILL_RESIZE_MENU, false);
- boolean withDelay = intent.getBooleanExtra(EXTRA_SHOW_MENU_WITH_DELAY, false);
- boolean showResizeHandle = intent.getBooleanExtra(EXTRA_SHOW_RESIZE_HANDLE, false);
- showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
- showResizeHandle);
- }
- }
-
- private void setActions(Rect stackBounds, List<RemoteAction> actions) {
- mActions.clear();
- mActions.addAll(actions);
- updateActionViews(stackBounds);
- }
-
- private void updateActionViews(Rect stackBounds) {
- ViewGroup expandContainer = findViewById(R.id.expand_container);
- ViewGroup actionsContainer = findViewById(R.id.actions_container);
- actionsContainer.setOnTouchListener((v, ev) -> {
- // Do nothing, prevent click through to parent
- return true;
- });
-
- if (mActions.isEmpty() || mMenuState == MENU_STATE_CLOSE) {
- actionsContainer.setVisibility(View.INVISIBLE);
- } else {
- actionsContainer.setVisibility(View.VISIBLE);
- if (mActionsGroup != null) {
- // Ensure we have as many buttons as actions
- final LayoutInflater inflater = LayoutInflater.from(this);
- while (mActionsGroup.getChildCount() < mActions.size()) {
- final ImageButton actionView = (ImageButton) inflater.inflate(
- R.layout.pip_menu_action, mActionsGroup, false);
- mActionsGroup.addView(actionView);
- }
-
- // Update the visibility of all views
- for (int i = 0; i < mActionsGroup.getChildCount(); i++) {
- mActionsGroup.getChildAt(i).setVisibility(i < mActions.size()
- ? View.VISIBLE
- : View.GONE);
- }
-
- // Recreate the layout
- final boolean isLandscapePip = stackBounds != null &&
- (stackBounds.width() > stackBounds.height());
- for (int i = 0; i < mActions.size(); i++) {
- final RemoteAction action = mActions.get(i);
- final ImageButton actionView = (ImageButton) mActionsGroup.getChildAt(i);
-
- // TODO: Check if the action drawable has changed before we reload it
- action.getIcon().loadDrawableAsync(this, d -> {
- d.setTint(Color.WHITE);
- actionView.setImageDrawable(d);
- }, mHandler);
- actionView.setContentDescription(action.getContentDescription());
- if (action.isEnabled()) {
- actionView.setOnClickListener(v -> {
- mHandler.post(() -> {
- try {
- action.getActionIntent().send();
- } catch (CanceledException e) {
- Log.w(TAG, "Failed to send action", e);
- }
- });
- });
- }
- actionView.setEnabled(action.isEnabled());
- actionView.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA);
-
- // Update the margin between actions
- LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
- actionView.getLayoutParams();
- lp.leftMargin = (isLandscapePip && i > 0) ? mBetweenActionPaddingLand : 0;
- }
- }
-
- // Update the expand container margin to adjust the center of the expand button to
- // account for the existence of the action container
- FrameLayout.LayoutParams expandedLp =
- (FrameLayout.LayoutParams) expandContainer.getLayoutParams();
- expandedLp.topMargin = getResources().getDimensionPixelSize(
- R.dimen.pip_action_padding);
- expandedLp.bottomMargin = getResources().getDimensionPixelSize(
- R.dimen.pip_expand_container_edge_margin);
- expandContainer.requestLayout();
- }
- }
-
- private void updateDismissFraction(float fraction) {
- int alpha;
- final float menuAlpha = 1 - fraction;
- if (mMenuState == MENU_STATE_FULL) {
- mMenuContainer.setAlpha(menuAlpha);
- mSettingsButton.setAlpha(menuAlpha);
- mDismissButton.setAlpha(menuAlpha);
- final float interpolatedAlpha =
- MENU_BACKGROUND_ALPHA * menuAlpha + DISMISS_BACKGROUND_ALPHA * fraction;
- alpha = (int) (interpolatedAlpha * 255);
- } else {
- if (mMenuState == MENU_STATE_CLOSE) {
- mDismissButton.setAlpha(menuAlpha);
- }
- alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255);
- }
- mBackgroundDrawable.setAlpha(alpha);
- }
-
- private void notifyMenuStateChange(int menuState, boolean resize, int callbackWhat) {
- mMenuState = menuState;
- mResize = resize;
- Message m = Message.obtain();
- m.what = PipMenuActivityController.MESSAGE_MENU_STATE_CHANGED;
- m.arg1 = menuState;
- m.arg2 = resize ? 1 : 0;
- if (callbackWhat != MESSAGE_INVALID_TYPE) {
- // This message could be sent across processes when in secondary user.
- // Make the receiver end sending back via our own Messenger
- m.replyTo = mMessenger;
- final Bundle data = new Bundle(1);
- data.putInt(PipMenuActivityController.EXTRA_MESSAGE_CALLBACK_WHAT, callbackWhat);
- m.obj = data;
- }
- sendMessage(m, "Could not notify controller of PIP menu visibility");
- }
-
- private void expandPip() {
- // Do not notify menu visibility when hiding the menu, the controller will do this when it
- // handles the message
- hideMenu(() -> {
- sendEmptyMessage(PipMenuActivityController.MESSAGE_EXPAND_PIP,
- "Could not notify controller to expand PIP");
- }, false /* notifyMenuVisibility */, false /* isDismissing */, true /* animate */);
- }
-
- private void dismissPip() {
- // Since tapping on the close-button invokes a double-tap wait callback in PipTouchHandler,
- // we want to disable animating the fadeout animation of the buttons in order to call on
- // PipTouchHandler#onPipDismiss fast enough.
- final boolean animate = mMenuState != MENU_STATE_CLOSE;
- // Do not notify menu visibility when hiding the menu, the controller will do this when it
- // handles the message
- hideMenu(() -> {
- sendEmptyMessage(PipMenuActivityController.MESSAGE_DISMISS_PIP,
- "Could not notify controller to dismiss PIP");
- }, false /* notifyMenuVisibility */, true /* isDismissing */, animate);
- }
-
- private void showSettings() {
- final Pair<ComponentName, Integer> topPipActivityInfo =
- PipUtils.getTopPipActivity(this, ActivityManager.getService());
- if (topPipActivityInfo.first != null) {
- final UserHandle user = UserHandle.of(topPipActivityInfo.second);
- final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
- Uri.fromParts("package", topPipActivityInfo.first.getPackageName(), null));
- settingsIntent.putExtra(Intent.EXTRA_USER_HANDLE, user);
- settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(settingsIntent);
- }
- }
-
- private void notifyActivityCallback(Messenger callback) {
- Message m = Message.obtain();
- m.what = PipMenuActivityController.MESSAGE_UPDATE_ACTIVITY_CALLBACK;
- m.replyTo = callback;
- m.arg1 = mResize ? 1 : 0;
- sendMessage(m, "Could not notify controller of activity finished");
- }
-
- private void sendEmptyMessage(int what, String errorMsg) {
- Message m = Message.obtain();
- m.what = what;
- sendMessage(m, errorMsg);
- }
-
- private void sendMessage(Message m, String errorMsg) {
- if (mToControllerMessenger == null) {
- return;
- }
- try {
- mToControllerMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, errorMsg, e);
- }
- }
-
- private void cancelDelayedFinish() {
- mHandler.removeCallbacks(mFinishRunnable);
- }
-
- private void repostDelayedFinish(int delay) {
- int recommendedTimeout = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
- FLAG_CONTENT_ICONS | FLAG_CONTENT_CONTROLS);
- mHandler.removeCallbacks(mFinishRunnable);
- mHandler.postDelayed(mFinishRunnable, recommendedTimeout);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 383f6b3..873ba26 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -19,27 +19,20 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import android.annotation.Nullable;
import android.app.ActivityManager.StackInfo;
-import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.RemoteAction;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.ParceledListSlice;
+import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.os.Bundle;
import android.os.Debug;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.WindowManager;
+import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.pip.phone.PipMediaController.ActionListener;
import com.android.systemui.shared.system.InputConsumerController;
@@ -58,30 +51,10 @@
private static final String TAG = "PipMenuActController";
private static final boolean DEBUG = false;
- public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
- public static final String EXTRA_ACTIONS = "actions";
- public static final String EXTRA_STACK_BOUNDS = "stack_bounds";
- public static final String EXTRA_ALLOW_TIMEOUT = "allow_timeout";
- public static final String EXTRA_WILL_RESIZE_MENU = "resize_menu_on_show";
- public static final String EXTRA_DISMISS_FRACTION = "dismiss_fraction";
- public static final String EXTRA_MENU_STATE = "menu_state";
- public static final String EXTRA_SHOW_MENU_WITH_DELAY = "show_menu_with_delay";
- public static final String EXTRA_SHOW_RESIZE_HANDLE = "show_resize_handle";
- public static final String EXTRA_MESSAGE_CALLBACK_WHAT = "message_callback_what";
-
- public static final int MESSAGE_MENU_STATE_CHANGED = 100;
- public static final int MESSAGE_EXPAND_PIP = 101;
- public static final int MESSAGE_DISMISS_PIP = 103;
- public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104;
- public static final int MESSAGE_SHOW_MENU = 107;
-
public static final int MENU_STATE_NONE = 0;
public static final int MENU_STATE_CLOSE = 1;
public static final int MENU_STATE_FULL = 2;
- // The duration to wait before we consider the start activity as having timed out
- private static final long START_ACTIVITY_REQUEST_TIMEOUT_MS = 300;
-
/**
* A listener interface to receive notification on changes in PIP.
*/
@@ -110,9 +83,8 @@
void onPipShowMenu();
}
- /** TODO(b/150319024): PipMenuActivity will move to a Window */
- private Class<?> mPipMenuActivityClass;
private Context mContext;
+ private PipTaskOrganizer mPipTaskOrganizer;
private PipMediaController mMediaController;
private InputConsumerController mInputConsumerController;
@@ -121,63 +93,7 @@
private ParceledListSlice<RemoteAction> mMediaActions;
private int mMenuState;
- // The dismiss fraction update is sent frequently, so use a temporary bundle for the message
- private Bundle mTmpDismissFractionData = new Bundle();
-
- private Runnable mOnAnimationEndRunnable;
- private boolean mStartActivityRequested;
- private long mStartActivityRequestedTime;
- private Messenger mToActivityMessenger;
- private Handler mHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_MENU_STATE_CHANGED: {
- final int menuState = msg.arg1;
- final boolean resize = msg.arg2 != 0;
- onMenuStateChanged(menuState, resize,
- getMenuStateChangeFinishedCallback(msg.replyTo, (Bundle) msg.obj));
- break;
- }
- case MESSAGE_EXPAND_PIP: {
- mListeners.forEach(Listener::onPipExpand);
- break;
- }
- case MESSAGE_DISMISS_PIP: {
- mListeners.forEach(Listener::onPipDismiss);
- break;
- }
- case MESSAGE_SHOW_MENU: {
- mListeners.forEach(Listener::onPipShowMenu);
- break;
- }
- case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
- mToActivityMessenger = msg.replyTo;
- setStartActivityRequested(false);
- if (mOnAnimationEndRunnable != null) {
- mOnAnimationEndRunnable.run();
- mOnAnimationEndRunnable = null;
- }
- // Mark the menu as invisible once the activity finishes as well
- if (mToActivityMessenger == null) {
- final boolean resize = msg.arg1 != 0;
- onMenuStateChanged(MENU_STATE_NONE, resize, null /* callback */);
- }
- break;
- }
- }
- }
- };
- private Messenger mMessenger = new Messenger(mHandler);
-
- private Runnable mStartActivityRequestedTimeoutRunnable = () -> {
- setStartActivityRequested(false);
- if (mOnAnimationEndRunnable != null) {
- mOnAnimationEndRunnable.run();
- mOnAnimationEndRunnable = null;
- }
- Log.e(TAG, "Expected start menu activity request timed out");
- };
+ private PipMenuView mPipMenuView;
private ActionListener mMediaActionListener = new ActionListener() {
@Override
@@ -187,39 +103,40 @@
}
};
- public PipMenuActivityController(Context context, Class<?> pipMenuActivityClass,
- PipMediaController mediaController, InputConsumerController inputConsumerController
+ public PipMenuActivityController(Context context,
+ PipMediaController mediaController, InputConsumerController inputConsumerController,
+ PipTaskOrganizer pipTaskOrganizer
) {
mContext = context;
mMediaController = mediaController;
mInputConsumerController = inputConsumerController;
- mPipMenuActivityClass = pipMenuActivityClass;
+ mPipTaskOrganizer = pipTaskOrganizer;
}
- public boolean isMenuActivityVisible() {
- return mToActivityMessenger != null;
+ public boolean isMenuVisible() {
+ return mPipMenuView != null && mMenuState != MENU_STATE_NONE;
}
public void onActivityPinned() {
+ if (mPipMenuView == null) {
+ WindowManager.LayoutParams lp =
+ getPipMenuLayoutParams(0, 0);
+ mPipMenuView = new PipMenuView(mContext, this);
+ mPipTaskOrganizer.attachPipMenuViewHost(mPipMenuView, lp);
+ }
mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
}
public void onActivityUnpinned() {
hideMenu();
mInputConsumerController.unregisterInputConsumer();
- setStartActivityRequested(false);
+ mPipTaskOrganizer.detachPipMenuViewHost();
+ mPipMenuView = null;
}
public void onPinnedStackAnimationEnded() {
- // Note: Only active menu activities care about this event
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_ANIMATION_ENDED;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu pinned animation ended", e);
- }
+ if (isMenuVisible()) {
+ mPipMenuView.onPipAnimationEnded();
}
}
@@ -236,27 +153,13 @@
* Updates the appearance of the menu and scrim on top of the PiP while dismissing.
*/
public void setDismissFraction(float fraction) {
+ final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
- Log.d(TAG, "setDismissFraction() hasActivity=" + (mToActivityMessenger != null)
+ Log.d(TAG, "setDismissFraction() isMenuVisible=" + isMenuVisible
+ " fraction=" + fraction);
}
- if (mToActivityMessenger != null) {
- mTmpDismissFractionData.clear();
- mTmpDismissFractionData.putFloat(EXTRA_DISMISS_FRACTION, fraction);
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_UPDATE_DISMISS_FRACTION;
- m.obj = mTmpDismissFractionData;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu to update dismiss fraction", e);
- }
- } else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
- // If we haven't requested the start activity, or if it previously took too long to
- // start, then start it
- startMenuActivity(MENU_STATE_NONE, null /* stackBounds */,
- false /* allowMenuTimeout */, false /* resizeMenuOnShow */,
- false /* withDelay */, false /* showResizeHandle */);
+ if (isMenuVisible) {
+ mPipMenuView.updateDismissFraction(fraction);
}
}
@@ -282,27 +185,11 @@
false /* withDelay */, showResizeHandle);
}
- private Runnable getMenuStateChangeFinishedCallback(@Nullable Messenger replyTo,
- @Nullable Bundle data) {
- if (replyTo == null || data == null) {
- return null;
- }
- return () -> {
- try {
- final Message m = Message.obtain();
- m.what = data.getInt(EXTRA_MESSAGE_CALLBACK_WHAT);
- replyTo.send(m);
- } catch (RemoteException e) {
- // ignored
- }
- };
- }
-
private void showMenuInternal(int menuState, Rect stackBounds, boolean allowMenuTimeout,
boolean willResizeMenu, boolean withDelay, boolean showResizeHandle) {
if (DEBUG) {
Log.d(TAG, "showMenu() state=" + menuState
- + " hasActivity=" + (mToActivityMessenger != null)
+ + " isMenuVisible=" + isMenuVisible()
+ " allowMenuTimeout=" + allowMenuTimeout
+ " willResizeMenu=" + willResizeMenu
+ " withDelay=" + withDelay
@@ -310,64 +197,34 @@
+ " callers=\n" + Debug.getCallers(5, " "));
}
- if (mToActivityMessenger != null) {
- Bundle data = new Bundle();
- data.putInt(EXTRA_MENU_STATE, menuState);
- if (stackBounds != null) {
- data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
- }
- data.putBoolean(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
- data.putBoolean(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
- data.putBoolean(EXTRA_SHOW_MENU_WITH_DELAY, withDelay);
- data.putBoolean(EXTRA_SHOW_RESIZE_HANDLE, showResizeHandle);
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_SHOW_MENU;
- m.obj = data;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu to show", e);
- }
- } else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
- // If we haven't requested the start activity, or if it previously took too long to
- // start, then start it
- startMenuActivity(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
- showResizeHandle);
+ if (mPipMenuView == null) {
+ Log.e(TAG, "PipMenu has not been attached yet.");
+ return;
}
+ mPipMenuView.showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
+ showResizeHandle);
}
/**
* Pokes the menu, indicating that the user is interacting with it.
*/
public void pokeMenu() {
+ final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
- Log.d(TAG, "pokeMenu() hasActivity=" + (mToActivityMessenger != null));
+ Log.d(TAG, "pokeMenu() isMenuVisible=" + isMenuVisible);
}
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_POKE_MENU;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify poke menu", e);
- }
+ if (isMenuVisible) {
+ mPipMenuView.pokeMenu();
}
}
private void fadeOutMenu() {
+ final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
- Log.d(TAG, "fadeOutMenu() state=" + mMenuState
- + " hasActivity=" + (mToActivityMessenger != null)
- + " callers=\n" + Debug.getCallers(5, " "));
+ Log.d(TAG, "fadeOutMenu() isMenuVisible=" + isMenuVisible);
}
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_FADE_OUT_MENU;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu to fade out", e);
- }
+ if (isMenuVisible) {
+ mPipMenuView.fadeOutMenu();
}
}
@@ -375,19 +232,14 @@
* Hides the menu activity.
*/
public void hideMenu() {
+ final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
Log.d(TAG, "hideMenu() state=" + mMenuState
- + " hasActivity=" + (mToActivityMessenger != null)
+ + " isMenuVisible=" + isMenuVisible
+ " callers=\n" + Debug.getCallers(5, " "));
}
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu to hide", e);
- }
+ if (isMenuVisible) {
+ mPipMenuView.hideMenu();
}
}
@@ -395,29 +247,11 @@
* Hides the menu activity.
*/
public void hideMenu(Runnable onStartCallback, Runnable onEndCallback) {
- if (mStartActivityRequested) {
- // If the menu has been start-requested, but not actually started, then we defer the
- // trigger callback until the menu has started and called back to the controller.
- mOnAnimationEndRunnable = onEndCallback;
- onStartCallback.run();
-
- // Fallback for b/63752800, we have started the PipMenuActivity but it has not made any
- // callbacks. Don't continue to wait for the menu to show past some timeout.
- mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
- mHandler.postDelayed(mStartActivityRequestedTimeoutRunnable,
- START_ACTIVITY_REQUEST_TIMEOUT_MS);
- } else if (mMenuState != MENU_STATE_NONE && mToActivityMessenger != null) {
+ if (isMenuVisible()) {
// If the menu is visible in either the closed or full state, then hide the menu and
// trigger the animation trigger afterwards
onStartCallback.run();
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
- m.obj = onEndCallback;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify hide menu", e);
- }
+ mPipMenuView.hideMenu(onEndCallback);
}
}
@@ -438,6 +272,18 @@
updateMenuActions();
}
+ void onPipExpand() {
+ mListeners.forEach(Listener::onPipExpand);
+ }
+
+ void onPipDismiss() {
+ mListeners.forEach(Listener::onPipDismiss);
+ }
+
+ void onPipShowMenu() {
+ mListeners.forEach(Listener::onPipShowMenu);
+ }
+
/**
* @return the best set of actions to show in the PiP menu.
*/
@@ -449,47 +295,20 @@
}
/**
- * Starts the menu activity on the top task of the pinned stack.
+ * Returns a default LayoutParams for the PIP Menu.
+ * @param width the PIP stack width.
+ * @param height the PIP stack height.
*/
- private void startMenuActivity(int menuState, Rect stackBounds, boolean allowMenuTimeout,
- boolean willResizeMenu, boolean withDelay, boolean showResizeHandle) {
- try {
- StackInfo pinnedStackInfo = ActivityTaskManager.getService().getStackInfo(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
- if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
- pinnedStackInfo.taskIds.length > 0) {
- Intent intent = new Intent(mContext, mPipMenuActivityClass);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
- intent.putExtra(EXTRA_ACTIONS, resolveMenuActions());
- if (stackBounds != null) {
- intent.putExtra(EXTRA_STACK_BOUNDS, stackBounds);
- }
- intent.putExtra(EXTRA_MENU_STATE, menuState);
- intent.putExtra(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
- intent.putExtra(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
- intent.putExtra(EXTRA_SHOW_MENU_WITH_DELAY, withDelay);
- intent.putExtra(EXTRA_SHOW_RESIZE_HANDLE, showResizeHandle);
- ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
- options.setLaunchTaskId(
- pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
- options.setTaskOverlay(true, true /* canResume */);
- mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
- setStartActivityRequested(true);
- } else {
- Log.e(TAG, "No PIP tasks found");
- }
- } catch (RemoteException e) {
- setStartActivityRequested(false);
- Log.e(TAG, "Error showing PIP menu activity", e);
- }
+ public static WindowManager.LayoutParams getPipMenuLayoutParams(int width, int height) {
+ return new WindowManager.LayoutParams(width, height,
+ WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSLUCENT);
}
/**
- * Updates the PiP menu activity with the best set of actions provided.
+ * Updates the PiP menu with the best set of actions provided.
*/
private void updateMenuActions() {
- if (mToActivityMessenger != null) {
+ if (isMenuVisible()) {
// Fetch the pinned stack bounds
Rect stackBounds = null;
try {
@@ -499,20 +318,10 @@
stackBounds = pinnedStackInfo.bounds;
}
} catch (RemoteException e) {
- Log.e(TAG, "Error showing PIP menu activity", e);
+ Log.e(TAG, "Error showing PIP menu", e);
}
- Bundle data = new Bundle();
- data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
- data.putParcelable(EXTRA_ACTIONS, resolveMenuActions());
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_UPDATE_ACTIONS;
- m.obj = data;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify menu activity to update actions", e);
- }
+ mPipMenuView.setActions(stackBounds, resolveMenuActions().getList());
}
}
@@ -524,17 +333,9 @@
}
/**
- * @return whether the time of the activity request has exceeded the timeout.
- */
- private boolean isStartActivityRequestedElapsed() {
- return (SystemClock.uptimeMillis() - mStartActivityRequestedTime)
- >= START_ACTIVITY_REQUEST_TIMEOUT_MS;
- }
-
- /**
* Handles changes in menu visibility.
*/
- private void onMenuStateChanged(int menuState, boolean resize, Runnable callback) {
+ void onMenuStateChanged(int menuState, boolean resize, Runnable callback) {
if (DEBUG) {
Log.d(TAG, "onMenuStateChanged() mMenuState=" + mMenuState
+ " menuState=" + menuState + " resize=" + resize
@@ -556,25 +357,14 @@
mMenuState = menuState;
}
- private void setStartActivityRequested(boolean requested) {
- mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
- mStartActivityRequested = requested;
- mStartActivityRequestedTime = requested ? SystemClock.uptimeMillis() : 0;
- }
-
/**
* Handles a pointer event sent from pip input consumer.
*/
void handlePointerEvent(MotionEvent ev) {
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_POINTER_EVENT;
- m.obj = ev;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not dispatch touch event", e);
- }
+ if (ev.isTouchEvent()) {
+ mPipMenuView.dispatchTouchEvent(ev);
+ } else {
+ mPipMenuView.dispatchGenericMotionEvent(ev);
}
}
@@ -582,15 +372,14 @@
* Tell the PIP Menu to recalculate its layout given its current position on the display.
*/
public void updateMenuLayout(Rect bounds) {
- if (mToActivityMessenger != null) {
- Message m = Message.obtain();
- m.what = PipMenuActivity.MESSAGE_UPDATE_MENU_LAYOUT;
- m.obj = bounds;
- try {
- mToActivityMessenger.send(m);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not dispatch touch event", e);
- }
+ final boolean isMenuVisible = isMenuVisible();
+ if (DEBUG) {
+ Log.d(TAG, "updateMenuLayout() state=" + mMenuState
+ + " isMenuVisible=" + isMenuVisible
+ + " callers=\n" + Debug.getCallers(5, " "));
+ }
+ if (isMenuVisible) {
+ mPipMenuView.updateMenuLayout(bounds);
}
}
@@ -598,9 +387,7 @@
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
pw.println(innerPrefix + "mMenuState=" + mMenuState);
- pw.println(innerPrefix + "mToActivityMessenger=" + mToActivityMessenger);
+ pw.println(innerPrefix + "mPipMenuView=" + mPipMenuView);
pw.println(innerPrefix + "mListeners=" + mListeners.size());
- pw.println(innerPrefix + "mStartActivityRequested=" + mStartActivityRequested);
- pw.println(innerPrefix + "mStartActivityRequestedTime=" + mStartActivityRequestedTime);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
new file mode 100644
index 0000000..993bfe0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
@@ -0,0 +1,497 @@
+/*
+ * 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.pip.phone;
+
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.provider.Settings.ACTION_PICTURE_IN_PICTURE_SETTINGS;
+import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS;
+import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
+
+import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
+import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
+import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.app.PendingIntent.CanceledException;
+import android.app.RemoteAction;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Pair;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Translucent window that gets started on top of a task in PIP to allow the user to control it.
+ */
+public class PipMenuView extends FrameLayout {
+
+ private static final String TAG = "PipMenuView";
+
+ private static final int MESSAGE_INVALID_TYPE = -1;
+ public static final int MESSAGE_MENU_EXPANDED = 8;
+
+ private static final int INITIAL_DISMISS_DELAY = 3500;
+ private static final int POST_INTERACTION_DISMISS_DELAY = 2000;
+ private static final long MENU_FADE_DURATION = 125;
+ private static final long MENU_SLOW_FADE_DURATION = 175;
+ private static final long MENU_SHOW_ON_EXPAND_START_DELAY = 30;
+
+ private static final float MENU_BACKGROUND_ALPHA = 0.3f;
+ private static final float DISMISS_BACKGROUND_ALPHA = 0.6f;
+
+ private static final float DISABLED_ACTION_ALPHA = 0.54f;
+
+ private static final boolean ENABLE_RESIZE_HANDLE = false;
+
+ private int mMenuState;
+ private boolean mResize = true;
+ private boolean mAllowMenuTimeout = true;
+ private boolean mAllowTouches = true;
+
+ private final List<RemoteAction> mActions = new ArrayList<>();
+
+ private AccessibilityManager mAccessibilityManager;
+ private Drawable mBackgroundDrawable;
+ private View mMenuContainer;
+ private LinearLayout mActionsGroup;
+ private int mBetweenActionPaddingLand;
+
+ private AnimatorSet mMenuContainerAnimator;
+ private PipMenuActivityController mController;
+
+ private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float alpha = (float) animation.getAnimatedValue();
+ mBackgroundDrawable.setAlpha((int) (MENU_BACKGROUND_ALPHA * alpha * 255));
+ }
+ };
+
+ private Handler mHandler = new Handler();
+
+ private final Runnable mHideMenuRunnable = this::hideMenu;
+
+ protected View mViewRoot;
+ protected View mSettingsButton;
+ protected View mDismissButton;
+ protected View mResizeHandle;
+ protected View mTopEndContainer;
+ protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
+
+ public PipMenuView(Context context, PipMenuActivityController controller) {
+ super(context, null, 0);
+ mContext = context;
+ mController = controller;
+
+ mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+ inflate(context, R.layout.pip_menu, this);
+
+ mBackgroundDrawable = new ColorDrawable(Color.BLACK);
+ mBackgroundDrawable.setAlpha(0);
+ mViewRoot = findViewById(R.id.background);
+ mViewRoot.setBackground(mBackgroundDrawable);
+ mMenuContainer = findViewById(R.id.menu_container);
+ mMenuContainer.setAlpha(0);
+ mTopEndContainer = findViewById(R.id.top_end_container);
+ mSettingsButton = findViewById(R.id.settings);
+ mSettingsButton.setAlpha(0);
+ mSettingsButton.setOnClickListener((v) -> {
+ if (v.getAlpha() != 0) {
+ showSettings();
+ }
+ });
+ mDismissButton = findViewById(R.id.dismiss);
+ mDismissButton.setAlpha(0);
+ mDismissButton.setOnClickListener(v -> dismissPip());
+ findViewById(R.id.expand_button).setOnClickListener(v -> {
+ if (mMenuContainer.getAlpha() != 0) {
+ expandPip();
+ }
+ });
+ // TODO (b/161710689): Remove this once focusability for Windowless window is working
+ findViewById(R.id.expand_button).setFocusable(false);
+ mDismissButton.setFocusable(false);
+ mSettingsButton.setFocusable(false);
+
+ mResizeHandle = findViewById(R.id.resize_handle);
+ mResizeHandle.setAlpha(0);
+ mActionsGroup = findViewById(R.id.actions_group);
+ mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
+ R.dimen.pip_between_action_padding_land);
+ mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(mContext);
+ mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
+ mResizeHandle, mSettingsButton, mDismissButton);
+
+ initAccessibility();
+ }
+
+ private void initAccessibility() {
+ this.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ String label = getResources().getString(R.string.pip_menu_title);
+ info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, label));
+ }
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if (action == ACTION_CLICK && mMenuState == MENU_STATE_CLOSE) {
+ mController.onPipShowMenu();
+ }
+ return super.performAccessibilityAction(host, action, args);
+ }
+ });
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ hideMenu();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (!mAllowTouches) {
+ return false;
+ }
+
+ if (mAllowMenuTimeout) {
+ repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
+ }
+
+ return super.dispatchTouchEvent(ev);
+ }
+
+ @Override
+ public boolean dispatchGenericMotionEvent(MotionEvent event) {
+ if (mAllowMenuTimeout) {
+ repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
+ }
+
+ return super.dispatchGenericMotionEvent(event);
+ }
+
+ void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ boolean resizeMenuOnShow, boolean withDelay, boolean showResizeHandle) {
+ mAllowMenuTimeout = allowMenuTimeout;
+ if (mMenuState != menuState) {
+ // Disallow touches if the menu needs to resize while showing, and we are transitioning
+ // to/from a full menu state.
+ boolean disallowTouchesUntilAnimationEnd = resizeMenuOnShow
+ && (mMenuState == MENU_STATE_FULL || menuState == MENU_STATE_FULL);
+ mAllowTouches = !disallowTouchesUntilAnimationEnd;
+ cancelDelayedHide();
+ updateActionViews(stackBounds);
+ if (mMenuContainerAnimator != null) {
+ mMenuContainerAnimator.cancel();
+ }
+ mMenuContainerAnimator = new AnimatorSet();
+ ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
+ mMenuContainer.getAlpha(), 1f);
+ menuAnim.addUpdateListener(mMenuBgUpdateListener);
+ ObjectAnimator settingsAnim = ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA,
+ mSettingsButton.getAlpha(), 1f);
+ ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
+ mDismissButton.getAlpha(), 1f);
+ ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
+ mResizeHandle.getAlpha(),
+ ENABLE_RESIZE_HANDLE && menuState == MENU_STATE_CLOSE && showResizeHandle
+ ? 1f : 0f);
+ if (menuState == MENU_STATE_FULL) {
+ mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
+ resizeAnim);
+ } else {
+ mMenuContainerAnimator.playTogether(dismissAnim, resizeAnim);
+ }
+ mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
+ mMenuContainerAnimator.setDuration(menuState == MENU_STATE_CLOSE
+ ? MENU_FADE_DURATION
+ : MENU_SLOW_FADE_DURATION);
+ if (allowMenuTimeout) {
+ mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ repostDelayedHide(INITIAL_DISMISS_DELAY);
+ }
+ });
+ }
+ if (withDelay) {
+ // starts the menu container animation after window expansion is completed
+ notifyMenuStateChange(menuState, resizeMenuOnShow, () -> {
+ if (mMenuContainerAnimator == null) {
+ return;
+ }
+ mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
+ mMenuContainerAnimator.start();
+ });
+ } else {
+ notifyMenuStateChange(menuState, resizeMenuOnShow, null);
+ mMenuContainerAnimator.start();
+ }
+ } else {
+ // If we are already visible, then just start the delayed dismiss and unregister any
+ // existing input consumers from the previous drag
+ if (allowMenuTimeout) {
+ repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
+ }
+ }
+ }
+
+ /**
+ * Different from {@link #hideMenu()}, this function does not try to finish this menu activity
+ * and instead, it fades out the controls by setting the alpha to 0 directly without menu
+ * visibility callbacks invoked.
+ */
+ void fadeOutMenu() {
+ mMenuContainer.setAlpha(0f);
+ mSettingsButton.setAlpha(0f);
+ mDismissButton.setAlpha(0f);
+ mResizeHandle.setAlpha(0f);
+ }
+
+ void pokeMenu() {
+ cancelDelayedHide();
+ }
+
+ void onPipAnimationEnded() {
+ mAllowTouches = true;
+ }
+
+ void updateMenuLayout(Rect bounds) {
+ mPipMenuIconsAlgorithm.onBoundsChanged(bounds);
+ }
+
+ void hideMenu() {
+ hideMenu(null);
+ }
+
+ void hideMenu(Runnable animationEndCallback) {
+ hideMenu(animationEndCallback, true /* notifyMenuVisibility */, false);
+ }
+
+ private void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility,
+ boolean animate) {
+ if (mMenuState != MENU_STATE_NONE) {
+ cancelDelayedHide();
+ if (notifyMenuVisibility) {
+ notifyMenuStateChange(MENU_STATE_NONE, mResize, null);
+ }
+ mMenuContainerAnimator = new AnimatorSet();
+ ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
+ mMenuContainer.getAlpha(), 0f);
+ menuAnim.addUpdateListener(mMenuBgUpdateListener);
+ ObjectAnimator settingsAnim = ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA,
+ mSettingsButton.getAlpha(), 0f);
+ ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
+ mDismissButton.getAlpha(), 0f);
+ ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
+ mResizeHandle.getAlpha(), 0f);
+ mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim, resizeAnim);
+ mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
+ mMenuContainerAnimator.setDuration(animate ? MENU_FADE_DURATION : 0);
+ mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (animationFinishedRunnable != null) {
+ animationFinishedRunnable.run();
+ }
+ }
+ });
+ mMenuContainerAnimator.start();
+ }
+ }
+
+ void setActions(Rect stackBounds, List<RemoteAction> actions) {
+ mActions.clear();
+ mActions.addAll(actions);
+ updateActionViews(stackBounds);
+ }
+
+ private void updateActionViews(Rect stackBounds) {
+ ViewGroup expandContainer = findViewById(R.id.expand_container);
+ ViewGroup actionsContainer = findViewById(R.id.actions_container);
+ actionsContainer.setOnTouchListener((v, ev) -> {
+ // Do nothing, prevent click through to parent
+ return true;
+ });
+
+ if (mActions.isEmpty() || mMenuState == MENU_STATE_CLOSE) {
+ actionsContainer.setVisibility(View.INVISIBLE);
+ } else {
+ actionsContainer.setVisibility(View.VISIBLE);
+ if (mActionsGroup != null) {
+ // Ensure we have as many buttons as actions
+ final LayoutInflater inflater = LayoutInflater.from(mContext);
+ while (mActionsGroup.getChildCount() < mActions.size()) {
+ final ImageButton actionView = (ImageButton) inflater.inflate(
+ R.layout.pip_menu_action, mActionsGroup, false);
+ mActionsGroup.addView(actionView);
+ }
+
+ // Update the visibility of all views
+ for (int i = 0; i < mActionsGroup.getChildCount(); i++) {
+ mActionsGroup.getChildAt(i).setVisibility(i < mActions.size()
+ ? View.VISIBLE
+ : View.GONE);
+ }
+
+ // Recreate the layout
+ final boolean isLandscapePip = stackBounds != null
+ && (stackBounds.width() > stackBounds.height());
+ for (int i = 0; i < mActions.size(); i++) {
+ final RemoteAction action = mActions.get(i);
+ final ImageButton actionView = (ImageButton) mActionsGroup.getChildAt(i);
+
+ // TODO: Check if the action drawable has changed before we reload it
+ action.getIcon().loadDrawableAsync(mContext, d -> {
+ d.setTint(Color.WHITE);
+ actionView.setImageDrawable(d);
+ }, mHandler);
+ actionView.setContentDescription(action.getContentDescription());
+ if (action.isEnabled()) {
+ actionView.setOnClickListener(v -> {
+ mHandler.post(() -> {
+ try {
+ action.getActionIntent().send();
+ } catch (CanceledException e) {
+ Log.w(TAG, "Failed to send action", e);
+ }
+ });
+ });
+ }
+ actionView.setEnabled(action.isEnabled());
+ actionView.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA);
+
+ // Update the margin between actions
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+ actionView.getLayoutParams();
+ lp.leftMargin = (isLandscapePip && i > 0) ? mBetweenActionPaddingLand : 0;
+ }
+ }
+
+ // Update the expand container margin to adjust the center of the expand button to
+ // account for the existence of the action container
+ FrameLayout.LayoutParams expandedLp =
+ (FrameLayout.LayoutParams) expandContainer.getLayoutParams();
+ expandedLp.topMargin = getResources().getDimensionPixelSize(
+ R.dimen.pip_action_padding);
+ expandedLp.bottomMargin = getResources().getDimensionPixelSize(
+ R.dimen.pip_expand_container_edge_margin);
+ expandContainer.requestLayout();
+ }
+ }
+
+ void updateDismissFraction(float fraction) {
+ int alpha;
+ final float menuAlpha = 1 - fraction;
+ if (mMenuState == MENU_STATE_FULL) {
+ mMenuContainer.setAlpha(menuAlpha);
+ mSettingsButton.setAlpha(menuAlpha);
+ mDismissButton.setAlpha(menuAlpha);
+ final float interpolatedAlpha =
+ MENU_BACKGROUND_ALPHA * menuAlpha + DISMISS_BACKGROUND_ALPHA * fraction;
+ alpha = (int) (interpolatedAlpha * 255);
+ } else {
+ if (mMenuState == MENU_STATE_CLOSE) {
+ mDismissButton.setAlpha(menuAlpha);
+ }
+ alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255);
+ }
+ mBackgroundDrawable.setAlpha(alpha);
+ }
+
+ private void notifyMenuStateChange(int menuState, boolean resize, Runnable callback) {
+ mMenuState = menuState;
+ mController.onMenuStateChanged(menuState, resize, callback);
+ }
+
+ private void expandPip() {
+ // Do not notify menu visibility when hiding the menu, the controller will do this when it
+ // handles the message
+ hideMenu(mController::onPipExpand, false /* notifyMenuVisibility */, true /* animate */);
+ }
+
+ private void dismissPip() {
+ // Since tapping on the close-button invokes a double-tap wait callback in PipTouchHandler,
+ // we want to disable animating the fadeout animation of the buttons in order to call on
+ // PipTouchHandler#onPipDismiss fast enough.
+ final boolean animate = mMenuState != MENU_STATE_CLOSE;
+ // Do not notify menu visibility when hiding the menu, the controller will do this when it
+ // handles the message
+ hideMenu(mController::onPipDismiss, false /* notifyMenuVisibility */, animate);
+ }
+
+ private void showSettings() {
+ final Pair<ComponentName, Integer> topPipActivityInfo =
+ PipUtils.getTopPipActivity(mContext, ActivityManager.getService());
+ if (topPipActivityInfo.first != null) {
+ final UserHandle user = UserHandle.of(topPipActivityInfo.second);
+ final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
+ Uri.fromParts("package", topPipActivityInfo.first.getPackageName(), null));
+ settingsIntent.putExtra(Intent.EXTRA_USER_HANDLE, user);
+ settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivity(settingsIntent);
+ }
+ }
+
+ private void cancelDelayedHide() {
+ mHandler.removeCallbacks(mHideMenuRunnable);
+ }
+
+ private void repostDelayedHide(int delay) {
+ int recommendedTimeout = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
+ FLAG_CONTENT_ICONS | FLAG_CONTENT_CONTROLS);
+ mHandler.removeCallbacks(mHideMenuRunnable);
+ mHandler.postDelayed(mHideMenuRunnable, recommendedTimeout);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 19138fdb..dcee2a5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -23,6 +23,8 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Debug;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.Choreographer;
@@ -66,6 +68,8 @@
private PipMenuActivityController mMenuController;
private PipSnapAlgorithm mSnapAlgorithm;
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
/** PIP's current bounds on the screen. */
private final Rect mBounds = new Rect();
@@ -128,8 +132,10 @@
SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
private final Consumer<Rect> mUpdateBoundsCallback = (Rect newBounds) -> {
- mMenuController.updateMenuLayout(newBounds);
- mBounds.set(newBounds);
+ mMainHandler.post(() -> {
+ mMenuController.updateMenuLayout(newBounds);
+ mBounds.set(newBounds);
+ });
};
/**
@@ -253,7 +259,9 @@
mTemporaryBounds.set(toBounds);
mPipTaskOrganizer.scheduleUserResizePip(mBounds, mTemporaryBounds,
(Rect newBounds) -> {
- mMenuController.updateMenuLayout(newBounds);
+ mMainHandler.post(() -> {
+ mMenuController.updateMenuLayout(newBounds);
+ });
});
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index 2800bb9..f6853ec 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -111,6 +111,7 @@
private InputMonitor mInputMonitor;
private InputEventReceiver mInputEventReceiver;
private PipTaskOrganizer mPipTaskOrganizer;
+ private PipMenuActivityController mPipMenuActivityController;
private PipUiEventLogger mPipUiEventLogger;
private int mCtrlType;
@@ -119,7 +120,7 @@
PipMotionHelper motionHelper, DeviceConfigProxy deviceConfig,
PipTaskOrganizer pipTaskOrganizer, Function<Rect, Rect> movementBoundsSupplier,
Runnable updateMovementBoundsRunnable, SysUiState sysUiState,
- PipUiEventLogger pipUiEventLogger) {
+ PipUiEventLogger pipUiEventLogger, PipMenuActivityController menuActivityController) {
mContext = context;
mDisplayId = context.getDisplayId();
mMainExecutor = context.getMainExecutor();
@@ -129,6 +130,7 @@
mMovementBoundsSupplier = movementBoundsSupplier;
mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
mSysUiState = sysUiState;
+ mPipMenuActivityController = menuActivityController;
mPipUiEventLogger = pipUiEventLogger;
context.getDisplay().getRealSize(mMaxSize);
@@ -298,6 +300,7 @@
float x = ev.getX();
float y = ev.getY();
if (action == MotionEvent.ACTION_DOWN) {
+ final Rect currentPipBounds = mMotionHelper.getBounds();
mLastResizeBounds.setEmpty();
mAllowGesture = isInValidSysUiState() && isWithinTouchRegion((int) x, (int) y);
if (mAllowGesture) {
@@ -305,6 +308,10 @@
mDownPoint.set(x, y);
mLastDownBounds.set(mMotionHelper.getBounds());
}
+ if (!currentPipBounds.contains((int) ev.getX(), (int) ev.getY())
+ && mPipMenuActivityController.isMenuVisible()) {
+ mPipMenuActivityController.hideMenu();
+ }
} else if (mAllowGesture) {
switch (action) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 1b84c14..9693f23 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -230,7 +230,7 @@
mPipResizeGestureHandler =
new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper,
deviceConfig, pipTaskOrganizer, this::getMovementBounds,
- this::updateMovementBounds, sysUiState, pipUiEventLogger);
+ this::updateMovementBounds, sysUiState, pipUiEventLogger, menuController);
mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler,
() -> mMenuController.showMenuWithDelay(MENU_STATE_FULL, mMotionHelper.getBounds(),
true /* allowMenuTimeout */, willResizeMenu(), shouldShowResizeHandle()),
@@ -773,10 +773,7 @@
* Updates the appearance of the menu and scrim on top of the PiP while dismissing.
*/
private void updateDismissFraction() {
- // Skip updating the dismiss fraction when the IME is showing. This is to work around an
- // issue where starting the menu activity for the dismiss overlay will steal the window
- // focus, which closes the IME.
- if (mMenuController != null && !mIsImeShowing) {
+ if (mMenuController != null) {
Rect bounds = mMotionHelper.getBounds();
final float target = mInsetBounds.bottom;
float fraction = 0f;
@@ -784,7 +781,7 @@
final float distance = bounds.bottom - target;
fraction = Math.min(distance / bounds.height(), 1f);
}
- if (Float.compare(fraction, 0f) != 0 || mMenuController.isMenuActivityVisible()) {
+ if (Float.compare(fraction, 0f) != 0 || mMenuController.isMenuVisible()) {
// Update if the fraction > 0, or if fraction == 0 and the menu was already visible
mMenuController.setDismissFraction(fraction);
}
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 8d0948b..a388fa3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -142,7 +142,6 @@
// Used to calculate the movement bounds
private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
private final Rect mTmpInsetBounds = new Rect();
- private final Rect mTmpNormalBounds = new Rect();
// Keeps track of the IME visibility to adjust the PiP when the IME is visible
private boolean mImeVisible;
@@ -216,10 +215,8 @@
public void onMovementBoundsChanged(boolean fromImeAdjustment) {
mHandler.post(() -> {
// Populate the inset / normal bounds and DisplayInfo from mPipBoundsHandler first.
- final Rect destinationBounds = new Rect();
- mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
- destinationBounds, mTmpDisplayInfo);
- mDefaultPipBounds.set(destinationBounds);
+ mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mPipBounds,
+ mDefaultPipBounds, mTmpDisplayInfo);
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index 651a4f3..5e5de58 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -114,6 +114,14 @@
notifyPipNotification();
}
}
+
+ @Override
+ public void onMetadataChanged(MediaMetadata metadata) {
+ if (updateMediaControllerMetadata() && mNotified) {
+ // update notification
+ notifyPipNotification();
+ }
+ }
};
private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
similarity index 61%
copy from packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
copy to packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
index 114c30e..8b8941a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
+++ b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
@@ -14,17 +14,19 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone.dagger;
+package com.android.systemui.power.dagger;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import com.android.systemui.power.PowerNotificationWarnings;
+import com.android.systemui.power.PowerUI;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
+import dagger.Binds;
+import dagger.Module;
-import javax.inject.Qualifier;
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface PipMenuActivityClass {
+/** Dagger Module for code in the power package. */
+@Module
+public interface PowerModule {
+ /** */
+ @Binds
+ PowerUI.WarningsUI provideWarningsUi(PowerNotificationWarnings controllerImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 8740581..8ff96c8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -22,6 +22,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.qs.AutoAddTracker;
+import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.ManagedProfileController;
@@ -29,6 +30,7 @@
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
+import dagger.Binds;
import dagger.Module;
import dagger.Provides;
@@ -56,4 +58,9 @@
manager.init();
return manager;
}
+
+
+ /** */
+ @Binds
+ QSHost provideQsHost(QSTileHost controllerImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index c0cc586..263bbdb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -98,6 +98,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import java.util.function.BiConsumer;
import javax.inject.Inject;
@@ -592,6 +593,8 @@
};
private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
+ private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener =
+ this::notifySplitScreenBoundsChanged;
// This is the death handler for the binder from the launcher service
private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
@@ -613,7 +616,6 @@
mNavBarControllerLazy = navBarControllerLazy;
mStatusBarWinController = statusBarWinController;
mConnectionBackoffAttempts = 0;
- mSplitScreenOptional = splitScreenOptional;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
com.android.internal.R.string.config_recentsComponentName));
mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
@@ -653,6 +655,10 @@
});
mCommandQueue = commandQueue;
+ splitScreenOptional.ifPresent(splitScreen ->
+ splitScreen.registerBoundsChangeListener(mSplitScreenBoundsChangeListener));
+ mSplitScreenOptional = splitScreenOptional;
+
// Listen for user setup
startTracking();
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 8ec3db5..3bf118d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -40,7 +40,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.LongRunning;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import java.io.IOException;
@@ -79,12 +79,12 @@
private final Executor mLongExecutor;
private final UiEventLogger mUiEventLogger;
private final NotificationManager mNotificationManager;
- private final CurrentUserContextTracker mUserContextTracker;
+ private final UserContextProvider mUserContextTracker;
@Inject
public RecordingService(RecordingController controller, @LongRunning Executor executor,
UiEventLogger uiEventLogger, NotificationManager notificationManager,
- CurrentUserContextTracker userContextTracker, KeyguardDismissUtil keyguardDismissUtil) {
+ UserContextProvider userContextTracker, KeyguardDismissUtil keyguardDismissUtil) {
mController = controller;
mLongExecutor = executor;
mUiEventLogger = uiEventLogger;
@@ -120,7 +120,7 @@
String action = intent.getAction();
Log.d(TAG, "onStartCommand " + action);
- int mCurrentUserId = mUserContextTracker.getCurrentUserContext().getUserId();
+ int mCurrentUserId = mUserContextTracker.getUserContext().getUserId();
UserHandle currentUser = new UserHandle(mCurrentUserId);
switch (action) {
case ACTION_START:
@@ -136,7 +136,7 @@
setTapsVisible(mShowTaps);
mRecorder = new ScreenMediaRecorder(
- mUserContextTracker.getCurrentUserContext(),
+ mUserContextTracker.getUserContext(),
mCurrentUserId,
mAudioSource,
this
@@ -156,7 +156,7 @@
// we want to post the notifications for that user, which is NOT current user
int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userId == -1) {
- userId = mUserContextTracker.getCurrentUserContext().getUserId();
+ userId = mUserContextTracker.getUserContext().getUserId();
}
Log.d(TAG, "notifying for user " + userId);
stopRecording(userId);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index dc47ab4..2b62a29 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -35,7 +35,7 @@
import android.widget.Switch;
import com.android.systemui.R;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import java.util.ArrayList;
import java.util.List;
@@ -51,7 +51,7 @@
private static final String TAG = "ScreenRecordDialog";
private final RecordingController mController;
- private final CurrentUserContextTracker mCurrentUserContextTracker;
+ private final UserContextProvider mUserContextProvider;
private Switch mTapsSwitch;
private Switch mAudioSwitch;
private Spinner mOptions;
@@ -59,9 +59,9 @@
@Inject
public ScreenRecordDialog(RecordingController controller,
- CurrentUserContextTracker currentUserContextTracker) {
+ UserContextProvider userContextProvider) {
mController = controller;
- mCurrentUserContextTracker = currentUserContextTracker;
+ mUserContextProvider = userContextProvider;
}
@Override
@@ -108,7 +108,7 @@
}
private void requestScreenCapture() {
- Context userContext = mCurrentUserContextTracker.getCurrentUserContext();
+ Context userContext = mUserContextProvider.getUserContext();
boolean showTaps = mTapsSwitch.isChecked();
ScreenRecordingAudioSource audioMode = mAudioSwitch.isChecked()
? (ScreenRecordingAudioSource) mOptions.getSelectedItem()
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index e24fbc6..7dd4edd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -573,7 +573,12 @@
private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
Insets screenInsets, boolean showFlash) {
- dismissScreenshot("new screenshot requested", true);
+ if (mScreenshotLayout.isAttachedToWindow()) {
+ if (!mDismissAnimation.isRunning()) { // if we didn't already dismiss for another reason
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED);
+ }
+ dismissScreenshot("new screenshot requested", true);
+ }
mScreenBitmap = screenshot;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
index 6b42f2e..74e0229 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
@@ -59,7 +59,9 @@
@UiEvent(doc = "screenshot interaction timed out")
SCREENSHOT_INTERACTION_TIMEOUT(310),
@UiEvent(doc = "screenshot explicitly dismissed")
- SCREENSHOT_EXPLICIT_DISMISSAL(311);
+ SCREENSHOT_EXPLICIT_DISMISSAL(311),
+ @UiEvent(doc = "screenshot reentered for new screenshot")
+ SCREENSHOT_REENTERED(640);
private final int mId;
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt
deleted file mode 100644
index d7c4caaa..0000000
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.settings
-
-import android.content.ContentResolver
-import android.content.Context
-import android.os.UserHandle
-import androidx.annotation.VisibleForTesting
-import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.util.Assert
-import java.lang.IllegalStateException
-
-/**
- * Tracks a reference to the context for the current user
- *
- * Constructor is injected at SettingsModule
- */
-class CurrentUserContextTracker internal constructor(
- private val sysuiContext: Context,
- broadcastDispatcher: BroadcastDispatcher
-) : CurrentUserContentResolverProvider {
- private val userTracker: CurrentUserTracker
- private var initialized = false
-
- private var _curUserContext: Context? = null
- val currentUserContext: Context
- get() {
- if (!initialized) {
- throw IllegalStateException("Must initialize before getting context")
- }
- return _curUserContext!!
- }
-
- override val currentUserContentResolver: ContentResolver
- get() = currentUserContext.contentResolver
-
- init {
- userTracker = object : CurrentUserTracker(broadcastDispatcher) {
- override fun onUserSwitched(newUserId: Int) {
- handleUserSwitched(newUserId)
- }
- }
- }
-
- fun initialize() {
- initialized = true
- userTracker.startTracking()
- _curUserContext = makeUserContext(userTracker.currentUserId)
- }
-
- @VisibleForTesting
- fun handleUserSwitched(newUserId: Int) {
- _curUserContext = makeUserContext(newUserId)
- }
-
- private fun makeUserContext(uid: Int): Context {
- Assert.isMainThread()
- return sysuiContext.createContextAsUser(UserHandle.of(uid), 0)
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt b/packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt
similarity index 84%
rename from packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt
rename to packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt
index 9d05843..e0c0c15 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt
@@ -18,7 +18,10 @@
import android.content.ContentResolver
-interface CurrentUserContentResolverProvider {
+/**
+ * Implemented by [UserTrackerImpl].
+ */
+interface UserContentResolverProvider {
- val currentUserContentResolver: ContentResolver
+ val userContentResolver: ContentResolver
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt b/packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt
similarity index 82%
copy from packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt
copy to packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt
index 9d05843..27af152 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt
@@ -16,9 +16,11 @@
package com.android.systemui.settings
-import android.content.ContentResolver
+import android.content.Context
-interface CurrentUserContentResolverProvider {
-
- val currentUserContentResolver: ContentResolver
+/**
+ * Implemented by [UserTrackerImpl].
+ */
+interface UserContextProvider {
+ val userContext: Context
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
new file mode 100644
index 0000000..26d408f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.settings
+
+import android.content.Context
+import android.content.pm.UserInfo
+import android.os.UserHandle
+import java.util.concurrent.Executor
+
+/**
+ * User tracker for SystemUI.
+ *
+ * This tracker provides async access to current user information, as well as callbacks for
+ * user/profile change.
+ */
+interface UserTracker : UserContentResolverProvider, UserContextProvider {
+
+ /**
+ * Current user's id.
+ */
+ val userId: Int
+
+ /**
+ * [UserHandle] for current user
+ */
+ val userHandle: UserHandle
+
+ /**
+ * List of profiles associated with the current user.
+ */
+ val userProfiles: List<UserInfo>
+
+ /**
+ * Add a [Callback] to be notified of chances, on a particular [Executor]
+ */
+ fun addCallback(callback: Callback, executor: Executor)
+
+ /**
+ * Remove a [Callback] previously added.
+ */
+ fun removeCallback(callback: Callback)
+
+ /**
+ * Ćallback for notifying of changes.
+ */
+ interface Callback {
+
+ /**
+ * Notifies that the current user has changed.
+ */
+ @JvmDefault
+ fun onUserChanged(newUser: Int, userContext: Context) {}
+
+ /**
+ * Notifies that the current user's profiles have changed.
+ */
+ @JvmDefault
+ fun onProfilesChanged(profiles: List<UserInfo>) {}
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
new file mode 100644
index 0000000..4cc0eee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -0,0 +1,240 @@
+/*
+ * 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.settings
+
+import android.content.BroadcastReceiver
+import android.content.ContentResolver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.UserInfo
+import android.os.Handler
+import android.os.UserHandle
+import android.os.UserManager
+import android.util.Log
+import androidx.annotation.GuardedBy
+import androidx.annotation.WorkerThread
+import com.android.systemui.Dumpable
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.Assert
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.lang.IllegalStateException
+import java.lang.ref.WeakReference
+import java.util.concurrent.Executor
+import kotlin.properties.ReadWriteProperty
+import kotlin.reflect.KProperty
+
+/**
+ * SystemUI cache for keeping track of the current user and associated values.
+ *
+ * The values provided asynchronously are NOT copies, but shared among all requesters. Do not
+ * modify them.
+ *
+ * This class purposefully doesn't use [BroadcastDispatcher] in order to receive the broadcast as
+ * soon as possible (and reduce its dependency graph).
+ * Other classes that want to listen to the broadcasts listened here SHOULD
+ * subscribe to this class instead.
+ *
+ * @see UserTracker
+ *
+ * Class constructed and initialized in [SettingsModule].
+ */
+class UserTrackerImpl internal constructor(
+ private val context: Context,
+ private val userManager: UserManager,
+ private val dumpManager: DumpManager,
+ private val backgroundHandler: Handler
+) : UserTracker, Dumpable, BroadcastReceiver() {
+
+ companion object {
+ private const val TAG = "UserTrackerImpl"
+ }
+
+ var initialized = false
+ private set
+
+ private val mutex = Any()
+
+ override var userId: Int by SynchronizedDelegate(context.userId)
+ private set
+
+ override var userHandle: UserHandle by SynchronizedDelegate(context.user)
+ private set
+
+ override var userContext: Context by SynchronizedDelegate(context)
+ private set
+
+ override val userContentResolver: ContentResolver
+ get() = userContext.contentResolver
+
+ /**
+ * Returns a [List<UserInfo>] of all profiles associated with the current user.
+ *
+ * The list returned is not a copy, so a copy should be made if its elements need to be
+ * modified.
+ */
+ override var userProfiles: List<UserInfo> by SynchronizedDelegate(emptyList())
+ private set
+
+ @GuardedBy("callbacks")
+ private val callbacks: MutableList<DataItem> = ArrayList()
+
+ fun initialize(startingUser: Int) {
+ if (initialized) {
+ return
+ }
+ initialized = true
+ setUserIdInternal(startingUser)
+
+ val filter = IntentFilter().apply {
+ addAction(Intent.ACTION_USER_SWITCHED)
+ addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED)
+ }
+ context.registerReceiverForAllUsers(this, filter, null /* permission */, backgroundHandler)
+
+ dumpManager.registerDumpable(TAG, this)
+ }
+
+ override fun onReceive(context: Context, intent: Intent) {
+ when (intent.action) {
+ Intent.ACTION_USER_SWITCHED -> {
+ handleSwitchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL))
+ }
+ Intent.ACTION_MANAGED_PROFILE_AVAILABLE, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE -> {
+ handleProfilesChanged()
+ }
+ }
+ }
+
+ private fun setUserIdInternal(user: Int): Pair<Context, List<UserInfo>> {
+ val profiles = userManager.getProfiles(user)
+ val handle = UserHandle(user)
+ val ctx = context.createContextAsUser(handle, 0)
+
+ synchronized(mutex) {
+ userId = user
+ userHandle = handle
+ userContext = ctx
+ userProfiles = profiles.map { UserInfo(it) }
+ }
+ return ctx to profiles
+ }
+
+ @WorkerThread
+ private fun handleSwitchUser(newUser: Int) {
+ Assert.isNotMainThread()
+ if (newUser == UserHandle.USER_NULL) {
+ Log.w(TAG, "handleSwitchUser - Couldn't get new id from intent")
+ return
+ }
+
+ if (newUser == userId) return
+ Log.i(TAG, "Switching to user $newUser")
+
+ val (ctx, profiles) = setUserIdInternal(newUser)
+
+ notifySubscribers {
+ onUserChanged(newUser, ctx)
+ onProfilesChanged(profiles)
+ }
+ }
+
+ @WorkerThread
+ private fun handleProfilesChanged() {
+ Assert.isNotMainThread()
+
+ val profiles = userManager.getProfiles(userId)
+ synchronized(mutex) {
+ userProfiles = profiles.map { UserInfo(it) } // save a "deep" copy
+ }
+ notifySubscribers {
+ onProfilesChanged(profiles)
+ }
+ }
+
+ override fun addCallback(callback: UserTracker.Callback, executor: Executor) {
+ synchronized(callbacks) {
+ callbacks.add(DataItem(WeakReference(callback), executor))
+ }
+ }
+
+ override fun removeCallback(callback: UserTracker.Callback) {
+ synchronized(callbacks) {
+ callbacks.removeIf { it.sameOrEmpty(callback) }
+ }
+ }
+
+ private inline fun notifySubscribers(crossinline action: UserTracker.Callback.() -> Unit) {
+ val list = synchronized(callbacks) {
+ callbacks.toList()
+ }
+ list.forEach {
+ if (it.callback.get() != null) {
+ it.executor.execute {
+ it.callback.get()?.action()
+ }
+ }
+ }
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.println("Initialized: $initialized")
+ if (initialized) {
+ pw.println("userId: $userId")
+ val ids = userProfiles.map { it.id }
+ pw.println("userProfiles: $ids")
+ }
+ val list = synchronized(callbacks) {
+ callbacks.toList()
+ }
+ pw.println("Callbacks:")
+ list.forEach {
+ it.callback.get()?.let {
+ pw.println(" $it")
+ }
+ }
+ }
+
+ private class SynchronizedDelegate<T : Any>(
+ private var value: T
+ ) : ReadWriteProperty<UserTrackerImpl, T> {
+
+ @GuardedBy("mutex")
+ override fun getValue(thisRef: UserTrackerImpl, property: KProperty<*>): T {
+ if (!thisRef.initialized) {
+ throw IllegalStateException("Must initialize before getting ${property.name}")
+ }
+ return synchronized(thisRef.mutex) { value }
+ }
+
+ @GuardedBy("mutex")
+ override fun setValue(thisRef: UserTrackerImpl, property: KProperty<*>, value: T) {
+ synchronized(thisRef.mutex) { this.value = value }
+ }
+ }
+}
+
+private data class DataItem(
+ val callback: WeakReference<UserTracker.Callback>,
+ val executor: Executor
+) {
+ fun sameOrEmpty(other: UserTracker.Callback): Boolean {
+ return callback.get()?.equals(other) ?: true
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java b/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
index b1ed772..7084d3f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
@@ -16,12 +16,18 @@
package com.android.systemui.settings.dagger;
+import android.app.ActivityManager;
import android.content.Context;
+import android.os.Handler;
+import android.os.UserManager;
-import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.settings.CurrentUserContentResolverProvider;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.settings.UserContentResolverProvider;
+import com.android.systemui.settings.UserContextProvider;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.settings.UserTrackerImpl;
import dagger.Binds;
import dagger.Module;
@@ -33,22 +39,27 @@
@Module
public abstract class SettingsModule {
- /**
- * Provides and initializes a CurrentUserContextTracker
- */
- @SysUISingleton
- @Provides
- static CurrentUserContextTracker provideCurrentUserContextTracker(
- Context context,
- BroadcastDispatcher broadcastDispatcher) {
- CurrentUserContextTracker tracker =
- new CurrentUserContextTracker(context, broadcastDispatcher);
- tracker.initialize();
- return tracker;
- }
@Binds
@SysUISingleton
- abstract CurrentUserContentResolverProvider bindCurrentUserContentResolverTracker(
- CurrentUserContextTracker tracker);
+ abstract UserContextProvider bindUserContextProvider(UserTracker tracker);
+
+ @Binds
+ @SysUISingleton
+ abstract UserContentResolverProvider bindUserContentResolverProvider(
+ UserTracker tracker);
+
+ @SysUISingleton
+ @Provides
+ static UserTracker provideUserTracker(
+ Context context,
+ UserManager userManager,
+ DumpManager dumpManager,
+ @Background Handler handler
+ ) {
+ int startingUser = ActivityManager.getCurrentUser();
+ UserTrackerImpl tracker = new UserTrackerImpl(context, userManager, dumpManager, handler);
+ tracker.initialize(startingUser);
+ return tracker;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 95f048b..fdf24b1 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -62,10 +62,8 @@
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
-import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.statusbar.FlingAnimationUtils;
import java.util.function.Consumer;
@@ -138,6 +136,7 @@
private final Rect mOtherInsetRect = new Rect();
private final Rect mLastResizeRect = new Rect();
private final Rect mTmpRect = new Rect();
+ private SplitScreenController mSplitScreenController;
private WindowManagerProxy mWindowManagerProxy;
private DividerWindowManager mWindowManager;
private VelocityTracker mVelocityTracker;
@@ -353,9 +352,11 @@
}
}
- public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState,
+ void injectDependencies(SplitScreenController splitScreenController,
+ DividerWindowManager windowManager, DividerState dividerState,
DividerCallbacks callback, SplitScreenTaskOrganizer tiles, SplitDisplayLayout sdl,
DividerImeController imeController, WindowManagerProxy wmProxy) {
+ mSplitScreenController = splitScreenController;
mWindowManager = windowManager;
mState = dividerState;
mCallback = callback;
@@ -697,8 +698,7 @@
mTmpRect.top = 0;
break;
}
- Dependency.get(OverviewProxyService.class)
- .notifySplitScreenBoundsChanged(mOtherTaskRect, mTmpRect);
+ mSplitScreenController.notifyBoundsChanged(mOtherTaskRect, mTmpRect);
}
private void cancelFlingAnimation() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java
index 91850cc..93b1f86 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreen.java
@@ -16,9 +16,11 @@
package com.android.systemui.stackdivider;
+import android.graphics.Rect;
import android.window.WindowContainerToken;
import java.io.PrintWriter;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
@@ -81,6 +83,9 @@
/** Registers listener that gets called whenever the existence of the divider changes. */
void registerInSplitScreenListener(Consumer<Boolean> listener);
+ /** Registers listener that gets called whenever the split screen bounds changes. */
+ void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener);
+
/** @return the container token for the secondary split root task. */
WindowContainerToken getSecondaryRoot();
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
index 11773f6..360b495 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenController.java
@@ -46,6 +46,7 @@
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
@@ -73,6 +74,8 @@
private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
new ArrayList<>();
+ private final ArrayList<WeakReference<BiConsumer<Rect, Rect>>> mBoundsChangedListeners =
+ new ArrayList<>();
private DividerWindowManager mWindowManager;
@@ -257,8 +260,8 @@
mView = (DividerView)
LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
- mView.injectDependencies(mWindowManager, mDividerState, mForcedResizableController, mSplits,
- mSplitLayout, mImePositionProcessor, mWindowManagerProxy);
+ mView.injectDependencies(this, mWindowManager, mDividerState, mForcedResizableController,
+ mSplits, mSplitLayout, mImePositionProcessor, mWindowManagerProxy);
mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
final int size = dctx.getResources().getDimensionPixelSize(
@@ -466,6 +469,24 @@
}
}
+ @Override
+ public void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
+ synchronized (mBoundsChangedListeners) {
+ mBoundsChangedListeners.add(new WeakReference<>(listener));
+ }
+ }
+
+ /** Notifies the bounds of split screen changed. */
+ void notifyBoundsChanged(Rect secondaryWindowBounds, Rect secondaryWindowInsets) {
+ synchronized (mBoundsChangedListeners) {
+ mBoundsChangedListeners.removeIf(wf -> {
+ BiConsumer<Rect, Rect> l = wf.get();
+ if (l != null) l.accept(secondaryWindowBounds, secondaryWindowInsets);
+ return l == null;
+ });
+ }
+ }
+
void startEnterSplit() {
update(mDisplayController.getDisplayContext(
mContext.getDisplayId()).getResources().getConfiguration());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index eca4c80..0df69a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -185,6 +185,7 @@
mAlertEntries.put(entry.getKey(), alertEntry);
onAlertEntryAdded(alertEntry);
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+ entry.setIsAlerting(true);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 44550b7..db2875a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -37,6 +37,8 @@
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.DynamicChildBindController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
@@ -45,13 +47,19 @@
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.ManagedProfileController;
+import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
+import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import dagger.Binds;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -136,6 +144,12 @@
return new SmartReplyController(entryManager, statusBarService, clickNotifier);
}
+
+ /** */
+ @Binds
+ NotificationRemoteInputManager.Callback provideNotificationRemoteInputManagerCallback(
+ StatusBarRemoteInputCallback callbackImpl);
+
/** */
@SysUISingleton
@Provides
@@ -179,4 +193,22 @@
static CommandQueue provideCommandQueue(Context context, ProtoTracer protoTracer) {
return new CommandQueue(context, protoTracer);
}
+
+ /**
+ */
+ @Binds
+ ManagedProfileController provideManagedProfileController(
+ ManagedProfileControllerImpl controllerImpl);
+
+ /**
+ */
+ @Binds
+ SysuiStatusBarStateController providesSysuiStatusBarStateController(
+ StatusBarStateControllerImpl statusBarStateControllerImpl);
+
+ /**
+ */
+ @Binds
+ StatusBarIconController provideStatusBarIconController(
+ StatusBarIconControllerImpl controllerImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 387247e..8ce9d94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -177,6 +177,7 @@
@Nullable private Long mPendingAnimationDuration;
private boolean mIsMarkedForUserTriggeredMovement;
private boolean mShelfIconVisible;
+ private boolean mIsAlerting;
/**
* @param sbn the StatusBarNotification from system server
@@ -955,6 +956,14 @@
mIsMarkedForUserTriggeredMovement = marked;
}
+ public void setIsAlerting(boolean isAlerting) {
+ mIsAlerting = isAlerting;
+ }
+
+ public boolean isAlerting() {
+ return mIsAlerting;
+ }
+
/** Information about a suggestion that is being edited. */
public static class EditedSuggestionInfo {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 6d01324..f3ed95b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -34,7 +34,7 @@
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -127,7 +127,7 @@
LauncherApps launcherApps,
ShortcutManager shortcutManager,
ChannelEditorDialogController channelEditorDialogController,
- CurrentUserContextTracker contextTracker,
+ UserContextProvider contextTracker,
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
AssistantFeedbackController assistantFeedbackController,
BubbleController bubbleController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 60074f6..7d418f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -52,7 +52,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -121,7 +121,7 @@
private final INotificationManager mNotificationManager;
private final LauncherApps mLauncherApps;
private final ShortcutManager mShortcutManager;
- private final CurrentUserContextTracker mContextTracker;
+ private final UserContextProvider mContextTracker;
private final Provider<PriorityOnboardingDialogController.Builder> mBuilderProvider;
private final UiEventLogger mUiEventLogger;
@@ -138,7 +138,7 @@
LauncherApps launcherApps,
ShortcutManager shortcutManager,
ChannelEditorDialogController channelEditorDialogController,
- CurrentUserContextTracker contextTracker,
+ UserContextProvider contextTracker,
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
AssistantFeedbackController assistantFeedbackController,
BubbleController bubbleController,
@@ -484,7 +484,7 @@
onSettingsClick,
onSnoozeClickListener,
iconFactoryLoader,
- mContextTracker.getCurrentUserContext(),
+ mContextTracker.getUserContext(),
mBuilderProvider,
mDeviceProvisionedController.isDeviceProvisioned(),
mMainHandler,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index d5e5531..0302b2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -81,17 +81,17 @@
private boolean mAppearing;
private float mPulseHeight = MAX_PULSE_HEIGHT;
private float mDozeAmount = 0.0f;
- private HeadsUpManager mHeadUpManager;
private Runnable mOnPulseHeightChangedListener;
private ExpandableNotificationRow mTrackedHeadsUpRow;
private float mAppearFraction;
+ /** Tracks the state from AlertingNotificationManager#hasNotifications() */
+ private boolean mHasAlertEntries;
+
public AmbientState(
Context context,
- @NonNull SectionProvider sectionProvider,
- HeadsUpManager headsUpManager) {
+ @NonNull SectionProvider sectionProvider) {
mSectionProvider = sectionProvider;
- mHeadUpManager = headsUpManager;
reload(context);
}
@@ -393,7 +393,7 @@
}
public boolean hasPulsingNotifications() {
- return mPulsing && mHeadUpManager != null && mHeadUpManager.hasNotifications();
+ return mPulsing && mHasAlertEntries;
}
public void setPulsing(boolean hasPulsing) {
@@ -408,10 +408,7 @@
}
public boolean isPulsing(NotificationEntry entry) {
- if (!mPulsing || mHeadUpManager == null) {
- return false;
- }
- return mHeadUpManager.isAlerting(entry.getKey());
+ return mPulsing && entry.isAlerting();
}
public boolean isPanelTracking() {
@@ -568,4 +565,8 @@
public float getAppearFraction() {
return mAppearFraction;
}
+
+ public void setHasAlertEntries(boolean hasAlertEntries) {
+ mHasAlertEntries = hasAlertEntries;
+ }
}
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 b1a9efe..3370773 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
@@ -92,8 +92,6 @@
import com.android.systemui.ExpandHelper;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
@@ -102,7 +100,6 @@
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;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
@@ -127,19 +124,14 @@
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
-import com.android.systemui.statusbar.notification.row.NotificationGuts;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
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.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
-import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
@@ -340,13 +332,10 @@
private HashSet<ExpandableView> mClearTransientViewsWhenFinished = new HashSet<>();
private HashSet<Pair<ExpandableNotificationRow, Boolean>> mHeadsUpChangeAnimations
= new HashSet<>();
- private HeadsUpManagerPhone mHeadsUpManager;
private final NotificationRoundnessManager mRoundnessManager;
private boolean mTrackingHeadsUp;
- private ScrimController mScrimController;
private boolean mForceNoOverlappingRendering;
private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
- private FalsingManager mFalsingManager;
private boolean mAnimationRunning;
private ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater
= new ViewTreeObserver.OnPreDrawListener() {
@@ -499,7 +488,6 @@
private Interpolator mHideXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
private NotificationPanelViewController mNotificationPanelController;
- private final NotificationGutsManager mNotificationGutsManager;
private final NotificationSectionsManager mSectionsManager;
private final ForegroundServiceSectionController mFgsSectionController;
private ForegroundServiceDungeonView mFgsSectionView;
@@ -513,6 +501,9 @@
private NotificationStackScrollLayoutController mController;
private boolean mKeyguardMediaControllorVisible;
+ private NotificationEntry mTopHeadsUpEntry;
+ private long mNumHeadsUp;
+ private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
new ExpandableView.OnHeightChangedListener() {
@@ -562,9 +553,6 @@
NotificationRoundnessManager notificationRoundnessManager,
DynamicPrivacyController dynamicPrivacyController,
SysuiStatusBarStateController statusbarStateController,
- HeadsUpManagerPhone headsUpManager,
- FalsingManager falsingManager,
- NotificationGutsManager notificationGutsManager,
NotificationSectionsManager notificationSectionsManager,
ForegroundServiceSectionController fgsSectionController,
ForegroundServiceDismissalFeatureController fgsFeatureController,
@@ -578,11 +566,6 @@
Resources res = getResources();
mRoundnessManager = notificationRoundnessManager;
-
- mNotificationGutsManager = notificationGutsManager;
- mHeadsUpManager = headsUpManager;
- mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
- mFalsingManager = falsingManager;
mFgsSectionController = fgsSectionController;
mSectionsManager = notificationSectionsManager;
@@ -594,7 +577,7 @@
});
mSections = mSectionsManager.createSectionsForBuckets();
- mAmbientState = new AmbientState(context, mSectionsManager, mHeadsUpManager);
+ mAmbientState = new AmbientState(context, mSectionsManager);
mBgColor = context.getColor(R.color.notification_shade_background_color);
int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
@@ -750,27 +733,6 @@
return false;
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public RemoteInputController.Delegate createDelegate() {
- return new RemoteInputController.Delegate() {
- public void setRemoteInputActive(NotificationEntry entry,
- boolean remoteInputActive) {
- mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
- entry.notifyHeightChanged(true /* needsAnimation */);
- updateFooter();
- }
-
- public void lockScrollTo(NotificationEntry entry) {
- NotificationStackScrollLayout.this.lockScrollTo(entry.getRow());
- }
-
- public void requestDisallowLongPressAndDismiss() {
- requestDisallowLongPress();
- requestDisallowDismiss();
- }
- };
- }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationSwipeActionHelper getSwipeActionHelper() {
return mSwipeHelper;
@@ -956,7 +918,7 @@
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void updateBackgroundDimming() {
+ void updateBackgroundDimming() {
// No need to update the background color if it's not being drawn.
if (!mShouldDrawNotificationBackground) {
return;
@@ -1472,11 +1434,10 @@
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getTopHeadsUpPinnedHeight() {
- NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
- if (topEntry == null) {
+ if (mTopHeadsUpEntry == null) {
return 0;
}
- ExpandableNotificationRow row = topEntry.getRow();
+ ExpandableNotificationRow row = mTopHeadsUpEntry.getRow();
if (row.isChildInGroup()) {
final NotificationEntry groupSummary =
mGroupManager.getGroupSummary(row.getEntry().getSbn());
@@ -1497,7 +1458,7 @@
int visibleNotifCount = getVisibleNotificationCount();
if (mEmptyShadeView.getVisibility() == GONE && visibleNotifCount > 0) {
if (isHeadsUpTransition()
- || (mHeadsUpManager.hasPinnedHeadsUp() && !mAmbientState.isDozing())) {
+ || (mInHeadsUpPinnedMode && !mAmbientState.isDozing())) {
if (mShelf.getVisibility() != GONE && visibleNotifCount > 1) {
appearPosition += mShelf.getIntrinsicHeight() + mPaddingBetweenElements;
}
@@ -1655,9 +1616,9 @@
ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
NotificationEntry entry = row.getEntry();
if (!mIsExpanded && row.isHeadsUp() && row.isPinned()
- && mHeadsUpManager.getTopEntry().getRow() != row
+ && mTopHeadsUpEntry.getRow() != row
&& mGroupManager.getGroupSummary(
- mHeadsUpManager.getTopEntry().getSbn())
+ mTopHeadsUpEntry.getSbn())
!= entry) {
continue;
}
@@ -2285,7 +2246,7 @@
// In current design, it only use the top HUN to treat all of HUNs
// although there are more than one HUNs
int contentHeight = mContentHeight;
- if (!isExpanded() && mHeadsUpManager.hasPinnedHeadsUp()) {
+ if (!isExpanded() && mInHeadsUpPinnedMode) {
contentHeight = mHeadsUpInset + getTopHeadsUpPinnedHeight();
}
int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight);
@@ -2636,7 +2597,7 @@
false /* shiftPulsingWithFirst */);
minTopPosition = firstVisibleSection.getBounds().top;
}
- boolean shiftPulsingWithFirst = mHeadsUpManager.getAllEntries().count() <= 1
+ boolean shiftPulsingWithFirst = mNumHeadsUp <= 1
&& (mAmbientState.isDozing()
|| (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard));
for (NotificationSection section : mSections) {
@@ -3511,7 +3472,7 @@
// Only animate if we still have pinned heads up, otherwise we just have the
// regular collapse animation of the lock screen
|| (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()
- && mHeadsUpManager.hasPinnedHeadsUp());
+ && mInHeadsUpPinnedMode);
if (performDisappearAnimation && !isHeadsUp) {
type = row.wasJustClicked()
? AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
@@ -3754,58 +3715,16 @@
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onTouchEvent(MotionEvent ev) {
- NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
- boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
- || ev.getActionMasked() == MotionEvent.ACTION_UP;
- handleEmptySpaceClick(ev);
- boolean expandWantsIt = false;
- boolean swipingInProgress = mSwipingInProgress;
- if (mIsExpanded && !swipingInProgress && !mOnlyScrollingInThisMotion && guts == null) {
- if (isCancelOrUp) {
- mExpandHelper.onlyObserveMovements(false);
- }
- boolean wasExpandingBefore = mExpandingNotification;
- expandWantsIt = mExpandHelper.onTouchEvent(ev);
- if (mExpandedInThisMotion && !mExpandingNotification && wasExpandingBefore
- && !mDisallowScrollingInThisMotion) {
- dispatchDownEventToScroller(ev);
- }
- }
- boolean scrollerWantsIt = false;
- if (mIsExpanded && !swipingInProgress && !mExpandingNotification
- && !mDisallowScrollingInThisMotion) {
- scrollerWantsIt = onScrollTouch(ev);
- }
- boolean horizontalSwipeWantsIt = false;
- if (!mIsBeingDragged
- && !mExpandingNotification
- && !mExpandedInThisMotion
- && !mOnlyScrollingInThisMotion
- && !mDisallowDismissInThisMotion) {
- horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
+ if (mTouchHandler != null && mTouchHandler.onTouchEvent(ev)) {
+ return true;
}
- // Check if we need to clear any snooze leavebehinds
- if (guts != null && !NotificationSwipeHelper.isTouchInView(ev, guts)
- && guts.getGutsContent() instanceof NotificationSnooze) {
- NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
- if ((ns.isExpanded() && isCancelOrUp)
- || (!horizontalSwipeWantsIt && scrollerWantsIt)) {
- // If the leavebehind is expanded we clear it on the next up event, otherwise we
- // clear it on the next non-horizontal swipe or expand event.
- checkSnoozeLeavebehind();
- }
- }
- if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
- mCheckForLeavebehind = true;
- }
- return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev);
+ return super.onTouchEvent(ev);
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private void dispatchDownEventToScroller(MotionEvent ev) {
+ void dispatchDownEventToScroller(MotionEvent ev) {
MotionEvent downEvent = MotionEvent.obtain(ev);
downEvent.setAction(MotionEvent.ACTION_DOWN);
onScrollTouch(downEvent);
@@ -3854,7 +3773,7 @@
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private boolean onScrollTouch(MotionEvent ev) {
+ boolean onScrollTouch(MotionEvent ev) {
if (!isScrollingEnabled()) {
return false;
}
@@ -3943,7 +3862,7 @@
customOverScrollBy((int) scrollAmount, mOwnScrollY,
range, getHeight() / 2);
// If we're scrolling, leavebehinds should be dismissed
- checkSnoozeLeavebehind();
+ mController.checkSnoozeLeavebehind();
}
}
break;
@@ -4061,44 +3980,14 @@
@Override
@ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onInterceptTouchEvent(MotionEvent ev) {
- initDownStates(ev);
- handleEmptySpaceClick(ev);
-
- NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
- boolean expandWantsIt = false;
- boolean swipingInProgress = mSwipingInProgress;
- if (!swipingInProgress && !mOnlyScrollingInThisMotion && guts == null) {
- expandWantsIt = mExpandHelper.onInterceptTouchEvent(ev);
+ if (mTouchHandler != null && mTouchHandler.onInterceptTouchEvent(ev)) {
+ return true;
}
- boolean scrollWantsIt = false;
- if (!swipingInProgress && !mExpandingNotification) {
- scrollWantsIt = onInterceptTouchEventScroll(ev);
- }
- boolean swipeWantsIt = false;
- if (!mIsBeingDragged
- && !mExpandingNotification
- && !mExpandedInThisMotion
- && !mOnlyScrollingInThisMotion
- && !mDisallowDismissInThisMotion) {
- swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
- }
- // Check if we need to clear any snooze leavebehinds
- boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
- if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
- !expandWantsIt && !scrollWantsIt) {
- mCheckForLeavebehind = false;
- mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- }
- if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
- mCheckForLeavebehind = true;
- }
- return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev);
+ return super.onInterceptTouchEvent(ev);
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private void handleEmptySpaceClick(MotionEvent ev) {
+ void handleEmptySpaceClick(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
final float touchSlop = getTouchSlop(ev);
@@ -4117,7 +4006,7 @@
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private void initDownStates(MotionEvent ev) {
+ void initDownStates(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mExpandedInThisMotion = false;
mOnlyScrollingInThisMotion = !mScroller.isFinished();
@@ -4139,7 +4028,7 @@
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- private boolean onInterceptTouchEventScroll(MotionEvent ev) {
+ boolean onInterceptTouchEventScroll(MotionEvent ev) {
if (!isScrollingEnabled()) {
return false;
}
@@ -4335,29 +4224,6 @@
}
@ShadeViewRefactor(RefactorComponent.INPUT)
- public void closeControlsIfOutsideTouch(MotionEvent ev) {
- NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
- NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
- View translatingParentView = mSwipeHelper.getTranslatingParentView();
- View view = null;
- if (guts != null && !guts.getGutsContent().isLeavebehind()) {
- // Only close visible guts if they're not a leavebehind.
- view = guts;
- } else if (menuRow != null && menuRow.isMenuVisible()
- && translatingParentView != null) {
- // Checking menu
- view = translatingParentView;
- }
- if (view != null && !NotificationSwipeHelper.isTouchInView(ev, view)) {
- // Touch was outside visible guts / menu notification, close what's visible
- mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */,
- false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- resetExposedMenuView(true /* animate */, true /* force */);
- }
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
void setSwipingInProgress(boolean swiping) {
mSwipingInProgress = swiping;
if (swiping) {
@@ -4392,32 +4258,15 @@
return Math.max(mMaxLayoutHeight - mContentHeight, 0);
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void checkSnoozeLeavebehind() {
- if (mCheckForLeavebehind) {
- mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- mCheckForLeavebehind = false;
- }
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void resetCheckSnoozeLeavebehind() {
- mCheckForLeavebehind = true;
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
void onExpansionStarted() {
mIsExpansionChanging = true;
mAmbientState.setExpansionChanging(true);
- checkSnoozeLeavebehind();
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
void onExpansionStopped() {
mIsExpansionChanging = false;
- resetCheckSnoozeLeavebehind();
mAmbientState.setExpansionChanging(false);
if (!mIsExpanded) {
resetScrollPosition();
@@ -5202,12 +5051,6 @@
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setScrimController(ScrimController scrimController) {
- mScrimController = scrimController;
- mScrimController.setScrimBehindChangeRunnable(this::updateBackgroundDimming);
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void forceNoOverlappingRendering(boolean force) {
mForceNoOverlappingRendering = force;
}
@@ -5811,23 +5654,6 @@
mCurrentUserId = userId;
}
- void onMenuShown(View row) {
- mSwipeHelper.onMenuShown(row);
- }
-
- void onMenuReset(View row) {
- View translatingParentView = mSwipeHelper.getTranslatingParentView();
- if (translatingParentView != null && row == translatingParentView) {
- mSwipeHelper.clearExposedMenuView();
- mSwipeHelper.clearTranslatingParentView();
- if (row instanceof ExpandableNotificationRow) {
- mHeadsUpManager.setMenuShown(
- ((ExpandableNotificationRow) row).getEntry(), false);
-
- }
- }
- }
-
void addSwipedOutView(View v) {
mSwipedOutViews.add(v);
}
@@ -5840,6 +5666,67 @@
mAmbientState.onDragFinished(view);
}
+ void setTopHeadsUpEntry(NotificationEntry topEntry) {
+ mTopHeadsUpEntry = topEntry;
+ }
+
+ void setNumHeadsUp(long numHeadsUp) {
+ mNumHeadsUp = numHeadsUp;
+ mAmbientState.setHasAlertEntries(numHeadsUp > 0);
+ }
+
+ boolean getSwipingInProgress() {
+ return mSwipingInProgress;
+ }
+
+ public boolean getIsExpanded() {
+ return mIsExpanded;
+ }
+
+ boolean getOnlyScrollingInThisMotion() {
+ return mOnlyScrollingInThisMotion;
+ }
+
+ ExpandHelper getExpandHelper() {
+ return mExpandHelper;
+ }
+
+ boolean isExpandingNotification() {
+ return mExpandingNotification;
+ }
+
+ boolean getDisallowScrollingInThisMotion() {
+ return mDisallowScrollingInThisMotion;
+ }
+
+ boolean isBeingDragged() {
+ return mIsBeingDragged;
+ }
+
+ boolean getExpandedInThisMotion() {
+ return mExpandedInThisMotion;
+ }
+
+ boolean getDisallowDismissInThisMotion() {
+ return mDisallowDismissInThisMotion;
+ }
+
+ void setCheckForLeaveBehind(boolean checkForLeaveBehind) {
+ mCheckForLeavebehind = checkForLeaveBehind;
+ }
+
+ void setTouchHandler(NotificationStackScrollLayoutController.TouchHandler touchHandler) {
+ mTouchHandler = touchHandler;
+ }
+
+ boolean isSwipingInProgress() {
+ return mSwipingInProgress;
+ }
+
+ boolean getCheckSnoozeLeaveBehind() {
+ return mCheckForLeavebehind;
+ }
+
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@@ -5935,7 +5822,7 @@
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void resetExposedMenuView(boolean animate, boolean force) {
+ private void resetExposedMenuView(boolean animate, boolean force) {
mSwipeHelper.resetExposedMenuView(animate, force);
}
@@ -6293,6 +6180,10 @@
mKeyguardMediaControllorVisible = keyguardMediaControllorVisible;
}
+ void resetCheckSnoozeLeavebehind() {
+ setCheckForLeaveBehind(true);
+ }
+
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
@ShadeViewRefactor(RefactorComponent.INPUT)
@@ -6345,7 +6236,7 @@
@Override
public void onTouchSlopExceeded() {
cancelLongPress();
- checkSnoozeLeavebehind();
+ mController.checkSnoozeLeavebehind();
}
@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
index 73b4cad..70892e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -34,6 +34,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.ExpandHelper;
+import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -58,7 +60,9 @@
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.NotificationGuts;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
@@ -70,6 +74,7 @@
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
@@ -100,6 +105,7 @@
private final NotificationSectionsManager mNotificationSectionsManager;
private final Resources mResources;
private final NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
+ private final ScrimController mScrimController;
private final KeyguardMediaController mKeyguardMediaController;
private final SysuiStatusBarStateController mStatusBarStateController;
private final KeyguardBypassController mKeyguardBypassController;
@@ -110,6 +116,7 @@
private NotificationStackScrollLayout mView;
private boolean mFadeNotificationsOnDismiss;
+ private NotificationSwipeHelper mSwipeHelper;
private final NotificationListContainerImpl mNotificationListContainer =
new NotificationListContainerImpl();
@@ -217,7 +224,16 @@
@Override
public void onMenuReset(View row) {
- mView.onMenuReset(row);
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ if (translatingParentView != null && row == translatingParentView) {
+ mSwipeHelper.clearExposedMenuView();
+ mSwipeHelper.clearTranslatingParentView();
+ if (row instanceof ExpandableNotificationRow) {
+ mHeadsUpManager.setMenuShown(
+ ((ExpandableNotificationRow) row).getEntry(), false);
+
+ }
+ }
}
@Override
@@ -228,7 +244,7 @@
.setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
.setType(MetricsEvent.TYPE_ACTION));
mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true);
- mView.onMenuShown(row);
+ mSwipeHelper.onMenuShown(row);
mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
false /* resetMenu */);
@@ -246,7 +262,7 @@
}
// Close the menu row since we went directly to the guts
- mView.resetExposedMenuView(false, true);
+ mSwipeHelper.resetExposedMenuView(false, true);
}
}
}
@@ -438,7 +454,31 @@
}
};
- private NotificationSwipeHelper mSwipeHelper;
+ private final OnHeadsUpChangedListener mOnHeadsUpChangedListener =
+ new OnHeadsUpChangedListener() {
+ @Override
+ public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
+ mView.setInHeadsUpPinnedMode(inPinnedMode);
+ }
+
+ @Override
+ public void onHeadsUpPinned(NotificationEntry entry) {
+
+ }
+
+ @Override
+ public void onHeadsUpUnPinned(NotificationEntry entry) {
+
+ }
+
+ @Override
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
+ long numEntries = mHeadsUpManager.getAllEntries().count();
+ NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
+ mView.setNumHeadsUp(numEntries);
+ mView.setTopHeadsUpEntry(topEntry);
+ }
+ };
@Inject
public NotificationStackScrollLayoutController(
@@ -460,7 +500,8 @@
NotificationSectionsManager notificationSectionsManager,
@Main Resources resources,
NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
- StatusBar statusBar) {
+ StatusBar statusBar,
+ ScrimController scrimController) {
mAllowLongPress = allowLongPress;
mNotificationGutsManager = notificationGutsManager;
mHeadsUpManager = headsUpManager;
@@ -480,11 +521,13 @@
mResources = resources;
mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder;
mStatusBar = statusBar;
+ mScrimController = scrimController;
}
public void attach(NotificationStackScrollLayout view) {
mView = view;
mView.setController(this);
+ mView.setTouchHandler(new TouchHandler());
mSwipeHelper = mNotificationSwipeHelperBuilder
.setSwipeDirection(SwipeHelper.X)
@@ -496,8 +539,12 @@
mSwipeHelper);
mHeadsUpManager.addListener(mNotificationRoundnessManager); // TODO: why is this here?
+ mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
+ mHeadsUpManager.setAnimationStateHandler(mView::setHeadsUpGoingAwayAnimationsAllowed);
mDynamicPrivacyController.addListener(mDynamicPrivacyControllerListener);
+ mScrimController.setScrimBehindChangeRunnable(mView::updateBackgroundDimming);
+
mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
mView.setCurrentUserid(mLockscreenUserManager.getCurrentUserId());
@@ -738,7 +785,12 @@
}
public void checkSnoozeLeavebehind() {
- mView.checkSnoozeLeavebehind();
+ if (mView.getCheckSnoozeLeaveBehind()) {
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ mView.setCheckForLeaveBehind(false);
+ }
}
public void setQsExpanded(boolean expanded) {
@@ -761,10 +813,6 @@
mView.updateTopPadding(qsHeight, animate);
}
- public void resetCheckSnoozeLeavebehind() {
- mView.resetCheckSnoozeLeavebehind();
- }
-
public boolean isScrolledToBottom() {
return mView.isScrolledToBottom();
}
@@ -815,9 +863,11 @@
public void onExpansionStarted() {
mView.onExpansionStarted();
+ checkSnoozeLeavebehind();
}
public void onExpansionStopped() {
+ mView.setCheckForLeaveBehind(false);
mView.onExpansionStopped();
}
@@ -910,7 +960,23 @@
}
public RemoteInputController.Delegate createDelegate() {
- return mView.createDelegate();
+ return new RemoteInputController.Delegate() {
+ public void setRemoteInputActive(NotificationEntry entry,
+ boolean remoteInputActive) {
+ mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
+ entry.notifyHeightChanged(true /* needsAnimation */);
+ updateFooter();
+ }
+
+ public void lockScrollTo(NotificationEntry entry) {
+ mView.lockScrollTo(entry.getRow());
+ }
+
+ public void requestDisallowLongPressAndDismiss() {
+ mView.requestDisallowLongPress();
+ mView.requestDisallowDismiss();
+ }
+ };
}
public void updateSectionBoundaries(String reason) {
@@ -958,18 +1024,10 @@
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);
}
@@ -1002,7 +1060,7 @@
return mView.calculateGapHeight(previousView, child, count);
}
- public NotificationRoundnessManager getNoticationRoundessManager() {
+ NotificationRoundnessManager getNoticationRoundessManager() {
return mNotificationRoundnessManager;
}
@@ -1010,6 +1068,32 @@
return mNotificationListContainer;
}
+ public void resetCheckSnoozeLeavebehind() {
+ mView.resetCheckSnoozeLeavebehind();
+ }
+
+ public void closeControlsIfOutsideTouch(MotionEvent ev) {
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ View view = null;
+ if (guts != null && !guts.getGutsContent().isLeavebehind()) {
+ // Only close visible guts if they're not a leavebehind.
+ view = guts;
+ } else if (menuRow != null && menuRow.isMenuVisible()
+ && translatingParentView != null) {
+ // Checking menu
+ view = translatingParentView;
+ }
+ if (view != null && !NotificationSwipeHelper.isTouchInView(ev, view)) {
+ // Touch was outside visible guts / menu notification, close what's visible
+ mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */,
+ false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ mSwipeHelper.resetExposedMenuView(true /* animate */, true /* force */);
+ }
+ }
+
private class NotificationListContainerImpl implements NotificationListContainer {
@Override
public void setChildTransferInProgress(boolean childTransferInProgress) {
@@ -1084,7 +1168,7 @@
@Override
public void resetExposedMenuView(boolean animate, boolean force) {
- mView.resetExposedMenuView(animate, force);
+ mSwipeHelper.resetExposedMenuView(animate, force);
}
@Override
@@ -1148,4 +1232,99 @@
mView.setWillExpand(willExpand);
}
}
+
+ class TouchHandler implements Gefingerpoken {
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ mView.initDownStates(ev);
+ mView.handleEmptySpaceClick(ev);
+
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ boolean expandWantsIt = false;
+ boolean swipingInProgress = mView.isSwipingInProgress();
+ if (!swipingInProgress && !mView.getOnlyScrollingInThisMotion() && guts == null) {
+ expandWantsIt = mView.getExpandHelper().onInterceptTouchEvent(ev);
+ }
+ boolean scrollWantsIt = false;
+ if (!swipingInProgress && !mView.isExpandingNotification()) {
+ scrollWantsIt = mView.onInterceptTouchEventScroll(ev);
+ }
+ boolean swipeWantsIt = false;
+ if (!mView.isBeingDragged()
+ && !mView.isExpandingNotification()
+ && !mView.getExpandedInThisMotion()
+ && !mView.getOnlyScrollingInThisMotion()
+ && !mView.getDisallowDismissInThisMotion()) {
+ swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
+ }
+ // Check if we need to clear any snooze leavebehinds
+ boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
+ if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
+ !expandWantsIt && !scrollWantsIt) {
+ mView.setCheckForLeaveBehind(false);
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ }
+ if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ mView.setCheckForLeaveBehind(true);
+ }
+ return swipeWantsIt || scrollWantsIt || expandWantsIt;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
+ || ev.getActionMasked() == MotionEvent.ACTION_UP;
+ mView.handleEmptySpaceClick(ev);
+ boolean expandWantsIt = false;
+ boolean swipingInProgress = mView.getSwipingInProgress();
+ boolean onlyScrollingInThisMotion = mView.getOnlyScrollingInThisMotion();
+ boolean expandingNotification = mView.isExpandingNotification();
+ if (mView.getIsExpanded() && !swipingInProgress && !onlyScrollingInThisMotion
+ && guts == null) {
+ ExpandHelper expandHelper = mView.getExpandHelper();
+ if (isCancelOrUp) {
+ expandHelper.onlyObserveMovements(false);
+ }
+ boolean wasExpandingBefore = expandingNotification;
+ expandWantsIt = expandHelper.onTouchEvent(ev);
+ expandingNotification = mView.isExpandingNotification();
+ if (mView.getExpandedInThisMotion() && !expandingNotification && wasExpandingBefore
+ && !mView.getDisallowScrollingInThisMotion()) {
+ mView.dispatchDownEventToScroller(ev);
+ }
+ }
+ boolean scrollerWantsIt = false;
+ if (mView.isExpanded() && !swipingInProgress && !expandingNotification
+ && !mView.getDisallowScrollingInThisMotion()) {
+ scrollerWantsIt = mView.onScrollTouch(ev);
+ }
+ boolean horizontalSwipeWantsIt = false;
+ if (!mView.isBeingDragged()
+ && !expandingNotification
+ && !mView.getExpandedInThisMotion()
+ && !onlyScrollingInThisMotion
+ && !mView.getDisallowDismissInThisMotion()) {
+ horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
+ }
+
+ // Check if we need to clear any snooze leavebehinds
+ if (guts != null && !NotificationSwipeHelper.isTouchInView(ev, guts)
+ && guts.getGutsContent() instanceof NotificationSnooze) {
+ NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
+ if ((ns.isExpanded() && isCancelOrUp)
+ || (!horizontalSwipeWantsIt && scrollerWantsIt)) {
+ // If the leavebehind is expanded we clear it on the next up event, otherwise we
+ // clear it on the next non-horizontal swipe or expand event.
+ checkSnoozeLeavebehind();
+ }
+ }
+ if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ mView.setCheckForLeaveBehind(true);
+ }
+ return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt;
+ }
+ }
}
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 e0576b7..1cd85e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -3072,9 +3072,6 @@
if (mKeyguardStatusBar != null) {
mKeyguardStatusBar.dump(fd, pw, args);
}
- if (mKeyguardStatusView != null) {
- mKeyguardStatusView.dump(fd, pw, args);
- }
}
public boolean hasActiveClearableNotifications() {
@@ -3143,15 +3140,13 @@
public void initDependencies(
StatusBar statusBar,
NotificationGroupManager groupManager,
- NotificationShelfController notificationShelfController,
- ScrimController scrimController) {
+ NotificationShelfController notificationShelfController) {
setStatusBar(statusBar);
setGroupManager(mGroupManager);
mNotificationStackScrollLayoutController.setNotificationPanelController(this);
mNotificationStackScrollLayoutController.setStatusBar(statusBar);
mNotificationStackScrollLayoutController.setGroupManager(groupManager);
mNotificationStackScrollLayoutController.setShelfController(notificationShelfController);
- mNotificationStackScrollLayoutController.setScrimController(scrimController);
updateShowEmptyShadeView();
mNotificationShelfController = notificationShelfController;
updateMaxDisplayedNotifications(true);
@@ -3549,7 +3544,6 @@
private class MyOnHeadsUpChangedListener implements OnHeadsUpChangedListener {
@Override
public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) {
- mNotificationStackScrollLayoutController.setInHeadsUpPinnedMode(inPinnedMode);
if (inPinnedMode) {
mHeadsUpExistenceChangedRunnable.run();
updateNotificationTranslucency();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 53cc267..a3d3c2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -52,6 +52,7 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
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.tuner.TunerService;
import com.android.systemui.util.InjectionInflationController;
@@ -83,6 +84,7 @@
private final NotificationShadeWindowView mView;
private final ShadeController mShadeController;
private final NotificationShadeDepthController mDepthController;
+ private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
private GestureDetector mGestureDetector;
private View mBrightnessMirror;
@@ -130,7 +132,8 @@
NotificationShadeDepthController depthController,
NotificationShadeWindowView notificationShadeWindowView,
NotificationPanelViewController notificationPanelViewController,
- SuperStatusBarViewFactory statusBarViewFactory) {
+ SuperStatusBarViewFactory statusBarViewFactory,
+ NotificationStackScrollLayoutController notificationStackScrollLayoutController) {
mInjectionInflationController = injectionInflationController;
mCoordinator = coordinator;
mPulseExpansionHandler = pulseExpansionHandler;
@@ -152,6 +155,7 @@
mNotificationPanelViewController = notificationPanelViewController;
mDepthController = depthController;
mStatusBarViewFactory = statusBarViewFactory;
+ mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
// This view is not part of the newly inflated expanded status bar.
mBrightnessMirror = mView.findViewById(R.id.brightness_mirror);
@@ -245,7 +249,7 @@
}
}
if (isDown) {
- mStackScrollLayout.closeControlsIfOutsideTouch(ev);
+ mNotificationStackScrollLayoutController.closeControlsIfOutsideTouch(ev);
}
if (mStatusBarStateController.isDozing()) {
mService.mDozeScrimController.extendPulse();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 11d0583..e95cf28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -141,6 +141,8 @@
private ScrimView mScrimBehind;
private ScrimView mScrimForBubble;
+ private Runnable mScrimBehindChangeRunnable;
+
private final KeyguardStateController mKeyguardStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final DozeParameters mDozeParameters;
@@ -241,6 +243,11 @@
mScrimInFront = scrimInFront;
mScrimForBubble = scrimForBubble;
+ if (mScrimBehindChangeRunnable != null) {
+ mScrimBehind.setChangeRunnable(mScrimBehindChangeRunnable);
+ mScrimBehindChangeRunnable = null;
+ }
+
final ScrimState[] states = ScrimState.values();
for (int i = 0; i < states.length; i++) {
states[i].init(mScrimInFront, mScrimBehind, mScrimForBubble, mDozeParameters,
@@ -934,7 +941,13 @@
}
public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
- mScrimBehind.setChangeRunnable(changeRunnable);
+ // TODO: remove this. This is necessary because of an order-of-operations limitation.
+ // The fix is to move more of these class into @StatusBarScope
+ if (mScrimBehind == null) {
+ mScrimBehindChangeRunnable = changeRunnable;
+ } else {
+ mScrimBehind.setChangeRunnable(changeRunnable);
+ }
}
public void setCurrentUser(int currentUser) {
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 115d164..5882879 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1160,8 +1160,7 @@
mNotificationPanelViewController.initDependencies(
this,
mGroupManager,
- mNotificationShelfController,
- mScrimController);
+ mNotificationShelfController);
BackDropView backdrop = mNotificationShadeWindowView.findViewById(R.id.backdrop);
mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
new file mode 100644
index 0000000..914105f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -0,0 +1,112 @@
+/*
+ * 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.policy.dagger;
+
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.CastControllerImpl;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.HotspotControllerImpl;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.KeyguardStateControllerImpl;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationControllerImpl;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.SecurityControllerImpl;
+import com.android.systemui.statusbar.policy.SensorPrivacyController;
+import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
+
+import dagger.Binds;
+import dagger.Module;
+
+
+/** Dagger Module for code in the statusbar.policy package. */
+@Module
+public interface StatusBarPolicyModule {
+ /** */
+ @Binds
+ BluetoothController provideBluetoothController(BluetoothControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ CastController provideCastController(CastControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ ExtensionController provideExtensionController(ExtensionControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ FlashlightController provideFlashlightController(FlashlightControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ KeyguardStateController provideKeyguardMonitor(KeyguardStateControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ HotspotController provideHotspotController(HotspotControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ LocationController provideLocationController(LocationControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ NetworkController provideNetworkController(NetworkControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ NextAlarmController provideNextAlarmController(NextAlarmControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ RotationLockController provideRotationLockController(RotationLockControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ SecurityController provideSecurityController(SecurityControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ SensorPrivacyController provideSensorPrivacyControllerImpl(
+ SensorPrivacyControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ UserInfoController provideUserInfoContrller(UserInfoControllerImpl controllerImpl);
+
+ /** */
+ @Binds
+ ZenModeController provideZenModeController(ZenModeControllerImpl controllerImpl);
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java b/packages/SystemUI/src/com/android/systemui/tuner/dagger/TunerModule.java
similarity index 62%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
rename to packages/SystemUI/src/com/android/systemui/tuner/dagger/TunerModule.java
index 114c30e..faf7b84 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/dagger/TunerModule.java
@@ -14,17 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone.dagger;
+package com.android.systemui.tuner.dagger;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerServiceImpl;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
+import dagger.Binds;
+import dagger.Module;
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface PipMenuActivityClass {
+/** Dagger Module for code in the tuner package. */
+@Module
+public interface TunerModule {
+ /** */
+ @Binds
+ TunerService provideTunerService(TunerServiceImpl controllerImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
index 3577bc0..bef05eb 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
@@ -17,7 +17,6 @@
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.SysUIComponent;
import com.android.systemui.dagger.SysUISingleton;
@@ -33,7 +32,6 @@
@Subcomponent(modules = {
DefaultComponentBinder.class,
DependencyProvider.class,
- DependencyBinder.class,
SystemUIBinder.class,
SystemUIModule.class,
TvSystemUIModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
new file mode 100644
index 0000000..5946af3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
@@ -0,0 +1,70 @@
+/*
+ * 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.util.concurrency;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.util.concurrent.Executor;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger Module for classes found within the concurrent package.
+ */
+@Module
+public abstract class GlobalConcurrencyModule {
+
+ /**
+ * Binds {@link ThreadFactoryImpl} to {@link ThreadFactory}.
+ */
+ @Binds
+ public abstract ThreadFactory bindExecutorFactory(ThreadFactoryImpl impl);
+
+ /** Main Looper */
+ @Provides
+ @Main
+ public static Looper provideMainLooper() {
+ return Looper.getMainLooper();
+ }
+
+ /**
+ * Main Handler.
+ *
+ * Prefer the Main Executor when possible.
+ */
+ @Provides
+ @Main
+ public static Handler provideMainHandler(@Main Looper mainLooper) {
+ return new Handler(mainLooper);
+ }
+
+ /**
+ * Provide a Main-Thread Executor.
+ */
+ @Provides
+ @Main
+ public static Executor provideMainExecutor(Context context) {
+ return context.getMainExecutor();
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
similarity index 85%
rename from packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
rename to packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index 628c808..b9b20c7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -16,7 +16,6 @@
package com.android.systemui.util.concurrency;
-import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -31,7 +30,6 @@
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
-import dagger.Binds;
import dagger.Module;
import dagger.Provides;
@@ -39,7 +37,7 @@
* Dagger Module for classes found within the concurrent package.
*/
@Module
-public abstract class ConcurrencyModule {
+public abstract class SysUIConcurrencyModule {
/** Background Looper */
@Provides
@SysUISingleton
@@ -62,13 +60,6 @@
return thread.getLooper();
}
- /** Main Looper */
- @Provides
- @Main
- public static Looper provideMainLooper() {
- return Looper.getMainLooper();
- }
-
/**
* Background Handler.
*
@@ -81,17 +72,6 @@
}
/**
- * Main Handler.
- *
- * Prefer the Main Executor when possible.
- */
- @Provides
- @Main
- public static Handler provideMainHandler(@Main Looper mainLooper) {
- return new Handler(mainLooper);
- }
-
- /**
* Provide a Background-Thread Executor by default.
*/
@Provides
@@ -121,15 +101,6 @@
}
/**
- * Provide a Main-Thread Executor.
- */
- @Provides
- @Main
- public static Executor provideMainExecutor(Context context) {
- return context.getMainExecutor();
- }
-
- /**
* Provide a Background-Thread Executor by default.
*/
@Provides
@@ -199,10 +170,4 @@
public static Executor provideUiBackgroundExecutor() {
return Executors.newSingleThreadExecutor();
}
-
- /**
- * Binds {@link ThreadFactoryImpl} to {@link ThreadFactory}.
- */
- @Binds
- public abstract ThreadFactory bindExecutorFactory(ThreadFactoryImpl impl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
copy to packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
index 114c30e..cdfa145 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
+++ b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
@@ -14,17 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone.dagger;
+package com.android.systemui.util.dagger;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.RingerModeTrackerImpl;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
+import dagger.Binds;
+import dagger.Module;
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface PipMenuActivityClass {
+/** Dagger Module for code in the util package. */
+@Module
+public interface UtilModule {
+ /** */
+ @Binds
+ RingerModeTracker provideRingerModeTracker(RingerModeTrackerImpl ringerModeTrackerImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 51ad30e..78f83d3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -49,6 +49,7 @@
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PixelFormat;
+import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
import android.media.AudioManager;
import android.media.AudioSystem;
@@ -71,6 +72,7 @@
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
+import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -109,7 +111,8 @@
* Methods ending in "H" must be called on the (ui) handler.
*/
public class VolumeDialogImpl implements VolumeDialog,
- ConfigurationController.ConfigurationListener {
+ ConfigurationController.ConfigurationListener,
+ ViewTreeObserver.OnComputeInternalInsetsListener {
private static final String TAG = Util.logTag(VolumeDialogImpl.class);
private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
@@ -126,6 +129,7 @@
private final H mHandler = new H();
private final VolumeDialogController mController;
private final DeviceProvisionedController mDeviceProvisionedController;
+ private final Region mTouchableRegion = new Region();
private Window mWindow;
private CustomDialog mDialog;
@@ -204,6 +208,33 @@
Dependency.get(ConfigurationController.class).removeCallback(this);
}
+ @Override
+ public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo internalInsetsInfo) {
+ // Set touchable region insets on the root dialog view. This tells WindowManager that
+ // touches outside of this region should not be delivered to the volume window, and instead
+ // go to the window below. This is the only way to do this - returning false in
+ // onDispatchTouchEvent results in the event being ignored entirely, rather than passed to
+ // the next window.
+ internalInsetsInfo.setTouchableInsets(
+ ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+
+ mTouchableRegion.setEmpty();
+
+ // Set the touchable region to the union of all child view bounds. We don't use touches on
+ // the volume dialog container itself, so this is fine.
+ for (int i = 0; i < mDialogView.getChildCount(); i++) {
+ final View view = mDialogView.getChildAt(i);
+ mTouchableRegion.op(
+ view.getLeft(),
+ view.getTop(),
+ view.getRight(),
+ view.getBottom(),
+ Region.Op.UNION);
+ }
+
+ internalInsetsInfo.touchableRegion.set(mTouchableRegion);
+ }
+
private void initDialog() {
mDialog = new CustomDialog(mContext);
@@ -235,6 +266,7 @@
mDialogView.setAlpha(0);
mDialog.setCanceledOnTouchOutside(true);
mDialog.setOnShowListener(dialog -> {
+ mDialogView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
if (!isLandscape()) mDialogView.setTranslationX(mDialogView.getWidth() / 2.0f);
mDialogView.setAlpha(0);
mDialogView.animate()
@@ -253,6 +285,11 @@
.start();
});
+ mDialog.setOnDismissListener(dialogInterface ->
+ mDialogView
+ .getViewTreeObserver()
+ .removeOnComputeInternalInsetsListener(VolumeDialogImpl.this));
+
mDialogView.setOnHoverListener((v, event) -> {
int action = event.getActionMasked();
mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
@@ -1369,6 +1406,11 @@
super(context, R.style.volume_dialog_theme);
}
+ /**
+ * NOTE: This will only be called for touches within the touchable region of the volume
+ * dialog, as returned by {@link #onComputeInternalInsets}. Other touches, even if they are
+ * within the bounds of the volume dialog, will fall through to the window below.
+ */
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
rescheduleTimeoutH();
@@ -1387,6 +1429,12 @@
mHandler.sendEmptyMessage(H.RECHECK_ALL);
}
+ /**
+ * NOTE: This will be called with ACTION_OUTSIDE MotionEvents for touches that occur outside
+ * of the touchable region of the volume dialog (as returned by
+ * {@link #onComputeInternalInsets}) even if those touches occurred within the bounds of the
+ * volume dialog.
+ */
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mShowing) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
copy to packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index 114c30e..1ef4c16 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipMenuActivityClass.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -14,17 +14,19 @@
* limitations under the License.
*/
-package com.android.systemui.pip.phone.dagger;
+package com.android.systemui.volume.dagger;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import com.android.systemui.volume.VolumeComponent;
+import com.android.systemui.volume.VolumeDialogComponent;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
+import dagger.Binds;
+import dagger.Module;
-import javax.inject.Qualifier;
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface PipMenuActivityClass {
+/** Dagger Module for code in the volume package. */
+@Module
+public interface VolumeModule {
+ /** */
+ @Binds
+ VolumeComponent provideVolumeComponent(VolumeDialogComponent volumeDialogComponent);
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 4922600..e4ff1b5 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -29,7 +29,11 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.stackdivider.SplitScreen;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.protolog.ShellProtoLogImpl;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.Optional;
import javax.inject.Inject;
@@ -108,4 +112,35 @@
}
});
}
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ // Handle commands if provided
+ for (int i = 0; i < args.length; i++) {
+ switch (args[i]) {
+ case "enable-text-logging": {
+ String[] groups = Arrays.copyOfRange(args, i + 1, args.length);
+ startTextLogging(groups);
+ pw.println("Starting logging on groups: " + Arrays.toString(groups));
+ return;
+ }
+ case "disable-text-logging": {
+ String[] groups = Arrays.copyOfRange(args, i + 1, args.length);
+ stopTextLogging(groups);
+ pw.println("Stopping logging on groups: " + Arrays.toString(groups));
+ return;
+ }
+ }
+ }
+
+ // Dump WMShell stuff here if no commands were handled
+ }
+
+ private void startTextLogging(String... groups) {
+ ShellProtoLogImpl.getSingleInstance().startTextLogging(mContext, groups);
+ }
+
+ private void stopTextLogging(String... groups) {
+ ShellProtoLogImpl.getSingleInstance().stopTextLogging(groups);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 7b45476..6a2ca44 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -22,8 +22,6 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.pip.phone.PipMenuActivity;
-import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.stackdivider.SplitScreenController;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -50,14 +48,6 @@
return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
}
- /** TODO(b/150319024): PipMenuActivity will move to a Window */
- @SysUISingleton
- @PipMenuActivityClass
- @Provides
- static Class<?> providePipMenuActivityClass() {
- return PipMenuActivity.class;
- }
-
@SysUISingleton
@Provides
static SplitScreen provideSplitScreen(Context context,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index c8e0f49..909acea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -69,7 +69,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -125,7 +125,7 @@
@Mock GlobalActionsPanelPlugin mWalletPlugin;
@Mock GlobalActionsPanelPlugin.PanelViewController mWalletController;
@Mock private Handler mHandler;
- @Mock private CurrentUserContextTracker mCurrentUserContextTracker;
+ @Mock private UserContextProvider mUserContextProvider;
private ControlsComponent mControlsComponent;
private TestableLooper mTestableLooper;
@@ -137,7 +137,7 @@
allowTestableLooperAsMainThread();
when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
- when(mCurrentUserContextTracker.getCurrentUserContext()).thenReturn(mContext);
+ when(mUserContextProvider.getUserContext()).thenReturn(mContext);
mControlsComponent = new ControlsComponent(
true,
() -> mControlsController,
@@ -176,7 +176,7 @@
mSysUiState,
mHandler,
mControlsComponent,
- mCurrentUserContextTracker
+ mUserContextProvider
);
mGlobalActionsDialog.setZeroDialogPressDelayForTesting();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index 4c9e141..3e37fde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -33,7 +33,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import org.junit.Before;
@@ -62,7 +62,7 @@
@Mock
private Executor mExecutor;
@Mock
- private CurrentUserContextTracker mUserContextTracker;
+ private UserContextProvider mUserContextTracker;
private KeyguardDismissUtil mKeyguardDismissUtil = new KeyguardDismissUtil() {
public void executeWhenUnlocked(ActivityStarter.OnDismissAction action,
boolean requiresShadeOpen) {
@@ -92,7 +92,7 @@
doNothing().when(mRecordingService).startForeground(anyInt(), any());
doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder();
- doReturn(mContext).when(mUserContextTracker).getCurrentUserContext();
+ doReturn(mContext).when(mUserContextTracker).getUserContext();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserContextTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserContextTrackerTest.kt
deleted file mode 100644
index 628c06a..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserContextTrackerTest.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.settings
-
-import android.content.Context
-import android.content.ContextWrapper
-import android.os.UserHandle
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.broadcast.BroadcastDispatcher
-import junit.framework.Assert.assertTrue
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.Mockito.mock
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper
-class CurrentUserContextTrackerTest : SysuiTestCase() {
-
- private lateinit var tracker: CurrentUserContextTracker
- @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- allowTestableLooperAsMainThread()
-
- // wrap Context so that tests don't throw for missing package errors
- val wrapped = object : ContextWrapper(context) {
- override fun createContextAsUser(user: UserHandle, flags: Int): Context {
- val mockContext = mock(Context::class.java)
- `when`(mockContext.user).thenReturn(user)
- `when`(mockContext.userId).thenReturn(user.identifier)
- return mockContext
- }
- }
-
- tracker = CurrentUserContextTracker(wrapped, broadcastDispatcher)
- tracker.initialize()
- }
-
- @Test
- fun testContextExistsAfterInit_noCrash() {
- tracker.currentUserContext
- }
-
- @Test
- fun testUserContextIsCorrectAfterUserSwitch() {
- // We always start out with system ui test
- assertTrue("Starting userId should be 0", tracker.currentUserContext.userId == 0)
-
- // WHEN user changes
- tracker.handleUserSwitched(1)
-
- // THEN user context should have the correct userId
- assertTrue("User has changed to userId 1, the context should reflect that",
- tracker.currentUserContext.userId == 1)
- }
-
- @Suppress("UNUSED_PARAMETER")
- @Test(expected = IllegalStateException::class)
- fun testContextTrackerThrowsExceptionWhenNotInitialized() {
- // GIVEN an uninitialized CurrentUserContextTracker
- val userTracker = CurrentUserContextTracker(context, broadcastDispatcher)
-
- // WHEN client asks for a context
- val userContext = userTracker.currentUserContext
-
- // THEN an exception is thrown
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
new file mode 100644
index 0000000..f76b50a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
@@ -0,0 +1,292 @@
+/*
+ * 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.settings
+
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.UserInfo
+import android.os.Handler
+import android.os.UserHandle
+import android.os.UserManager
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.ArgumentMatchers.isNull
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import java.util.concurrent.Executor
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class UserTrackerImplTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var context: Context
+ @Mock
+ private lateinit var userManager: UserManager
+ @Mock(stubOnly = true)
+ private lateinit var dumpManager: DumpManager
+ @Mock(stubOnly = true)
+ private lateinit var handler: Handler
+
+ private val executor = Executor(Runnable::run)
+ private lateinit var tracker: UserTrackerImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ `when`(context.userId).thenReturn(UserHandle.USER_SYSTEM)
+ `when`(context.user).thenReturn(UserHandle.SYSTEM)
+ `when`(context.createContextAsUser(any(), anyInt())).thenAnswer { invocation ->
+ val user = invocation.getArgument<UserHandle>(0)
+ `when`(context.user).thenReturn(user)
+ `when`(context.userId).thenReturn(user.identifier)
+ context
+ }
+ `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ val info = UserInfo(invocation.getArgument<Int>(0), "", UserInfo.FLAG_FULL)
+ listOf(info)
+ }
+
+ tracker = UserTrackerImpl(context, userManager, dumpManager, handler)
+ }
+
+ @Test
+ fun testNotInitialized() {
+ assertThat(tracker.initialized).isFalse()
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserIdBeforeInitThrowsException() {
+ tracker.userId
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserHandleBeforeInitThrowsException() {
+ tracker.userHandle
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserContextBeforeInitThrowsException() {
+ tracker.userContext
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserContentResolverBeforeInitThrowsException() {
+ tracker.userContentResolver
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun testGetUserProfilesBeforeInitThrowsException() {
+ tracker.userProfiles
+ }
+
+ @Test
+ fun testInitialize() {
+ tracker.initialize(0)
+
+ assertThat(tracker.initialized).isTrue()
+ }
+
+ @Test
+ fun testReceiverRegisteredOnInitialize() {
+ tracker.initialize(0)
+
+ val captor = ArgumentCaptor.forClass(IntentFilter::class.java)
+
+ verify(context).registerReceiverForAllUsers(
+ eq(tracker), capture(captor), isNull(), eq(handler))
+ }
+
+ @Test
+ fun testInitialValuesSet() {
+ val testID = 4
+ tracker.initialize(testID)
+
+ verify(userManager).getProfiles(testID)
+
+ assertThat(tracker.userId).isEqualTo(testID)
+ assertThat(tracker.userHandle).isEqualTo(UserHandle.of(testID))
+ assertThat(tracker.userContext.userId).isEqualTo(testID)
+ assertThat(tracker.userContext.user).isEqualTo(UserHandle.of(testID))
+ assertThat(tracker.userProfiles).hasSize(1)
+
+ val info = tracker.userProfiles[0]
+ assertThat(info.id).isEqualTo(testID)
+ }
+
+ @Test
+ fun testUserSwitch() {
+ tracker.initialize(0)
+ val newID = 5
+
+ val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, newID)
+ tracker.onReceive(context, intent)
+
+ verify(userManager).getProfiles(newID)
+
+ assertThat(tracker.userId).isEqualTo(newID)
+ assertThat(tracker.userHandle).isEqualTo(UserHandle.of(newID))
+ assertThat(tracker.userContext.userId).isEqualTo(newID)
+ assertThat(tracker.userContext.user).isEqualTo(UserHandle.of(newID))
+ assertThat(tracker.userProfiles).hasSize(1)
+
+ val info = tracker.userProfiles[0]
+ assertThat(info.id).isEqualTo(newID)
+ }
+
+ @Test
+ fun testManagedProfileAvailable() {
+ tracker.initialize(0)
+ val profileID = tracker.userId + 10
+
+ `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ val id = invocation.getArgument<Int>(0)
+ val info = UserInfo(id, "", UserInfo.FLAG_FULL)
+ val infoProfile = UserInfo(
+ id + 10,
+ "",
+ "",
+ UserInfo.FLAG_MANAGED_PROFILE,
+ UserManager.USER_TYPE_PROFILE_MANAGED
+ )
+ infoProfile.profileGroupId = id
+ listOf(info, infoProfile)
+ }
+
+ val intent = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+ tracker.onReceive(context, intent)
+
+ assertThat(tracker.userProfiles.map { it.id }).containsExactly(tracker.userId, profileID)
+ }
+
+ @Test
+ fun testCallbackNotCalledOnAdd() {
+ tracker.initialize(0)
+ val callback = TestCallback()
+
+ tracker.addCallback(callback, executor)
+
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
+ assertThat(callback.calledOnUserChanged).isEqualTo(0)
+ }
+
+ @Test
+ fun testCallbackCalledOnUserChanged() {
+ tracker.initialize(0)
+ val callback = TestCallback()
+ tracker.addCallback(callback, executor)
+
+ val newID = 5
+
+ val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, newID)
+ tracker.onReceive(context, intent)
+
+ assertThat(callback.calledOnUserChanged).isEqualTo(1)
+ assertThat(callback.lastUser).isEqualTo(newID)
+ assertThat(callback.lastUserContext?.userId).isEqualTo(newID)
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(1)
+ assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(newID)
+ }
+
+ @Test
+ fun testCallbackCalledOnProfileChanged() {
+ tracker.initialize(0)
+ val callback = TestCallback()
+ tracker.addCallback(callback, executor)
+ val profileID = tracker.userId + 10
+
+ `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ val id = invocation.getArgument<Int>(0)
+ val info = UserInfo(id, "", UserInfo.FLAG_FULL)
+ val infoProfile = UserInfo(
+ id + 10,
+ "",
+ "",
+ UserInfo.FLAG_MANAGED_PROFILE,
+ UserManager.USER_TYPE_PROFILE_MANAGED
+ )
+ infoProfile.profileGroupId = id
+ listOf(info, infoProfile)
+ }
+
+ val intent = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+
+ tracker.onReceive(context, intent)
+
+ assertThat(callback.calledOnUserChanged).isEqualTo(0)
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(1)
+ assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(0, profileID)
+ }
+
+ @Test
+ fun testCallbackRemoved() {
+ tracker.initialize(0)
+ val newID = 5
+ val profileID = newID + 10
+
+ val callback = TestCallback()
+ tracker.addCallback(callback, executor)
+ tracker.removeCallback(callback)
+
+ val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, 5)
+ tracker.onReceive(context, intent)
+
+ val intentProfiles = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
+
+ tracker.onReceive(context, intentProfiles)
+
+ assertThat(callback.calledOnUserChanged).isEqualTo(0)
+ assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
+ }
+
+ private class TestCallback : UserTracker.Callback {
+ var calledOnUserChanged = 0
+ var calledOnProfilesChanged = 0
+ var lastUser: Int? = null
+ var lastUserContext: Context? = null
+ var lastUserProfiles = emptyList<UserInfo>()
+
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ calledOnUserChanged++
+ lastUser = newUser
+ lastUserContext = userContext
+ }
+
+ override fun onProfilesChanged(profiles: List<UserInfo>) {
+ calledOnProfilesChanged++
+ lastUserProfiles = profiles
+ }
+ }
+}
\ No newline at end of file
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 c2c40ca..e1668ca 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
@@ -69,7 +69,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.settings.CurrentUserContextTracker;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
@@ -128,7 +128,7 @@
@Mock private ShortcutManager mShortcutManager;
@Mock private ChannelEditorDialogController mChannelEditorDialogController;
@Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
- @Mock private CurrentUserContextTracker mContextTracker;
+ @Mock private UserContextProvider mContextTracker;
@Mock private BubbleController mBubbleController;
@Mock(answer = Answers.RETURNS_SELF)
private PriorityOnboardingDialogController.Builder mBuilder;
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 fa9ea6b..62b741c 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
@@ -78,12 +78,10 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.KeyguardBypassEnabledProvider;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
-import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.leak.LeakDetector;
@@ -122,7 +120,6 @@
@Mock private EmptyShadeView mEmptyShadeView;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private RemoteInputController mRemoteInputController;
- @Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private MetricsLogger mMetricsLogger;
@Mock private NotificationRoundnessManager mNotificationRoundnessManager;
@Mock private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
@@ -203,9 +200,6 @@
mNotificationRoundnessManager,
mock(DynamicPrivacyController.class),
mStatusBarStateController,
- mHeadsUpManager,
- new FalsingManagerFake(),
- mock(NotificationGutsManager.class),
mNotificationSectionsManager,
mock(ForegroundServiceSectionController.class),
mock(ForegroundServiceDismissalFeatureController.class),
@@ -220,7 +214,6 @@
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelfController(notificationShelfController);
mStackScroller.setStatusBar(mBar);
- mStackScroller.setScrimController(mock(ScrimController.class));
mStackScroller.setGroupManager(mGroupManager);
mStackScroller.setEmptyShadeView(mEmptyShadeView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
index 4fffd3e..f5d9fa0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
@@ -49,6 +49,8 @@
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
+import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -110,6 +112,8 @@
private NotificationSwipeHelper mNotificationSwipeHelper;
@Mock
private StatusBar mStatusBar;
+ @Mock
+ private ScrimController mScrimController;
private NotificationStackScrollLayoutController mController;
@@ -138,7 +142,8 @@
mNotificationSectionsManager,
mResources,
mNotificationSwipeHelperBuilder,
- mStatusBar
+ mStatusBar,
+ mScrimController
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
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 a9484af..453baa5 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
@@ -112,8 +112,6 @@
@Mock
private ViewGroup mBigClockContainer;
@Mock
- private ScrimController mScrimController;
- @Mock
private NotificationIconAreaController mNotificationAreaController;
@Mock
private HeadsUpManagerPhone mHeadsUpManager;
@@ -271,8 +269,7 @@
mNotificationPanelViewController.initDependencies(
mStatusBar,
mGroupManager,
- mNotificationShelfController,
- mScrimController);
+ mNotificationShelfController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
mNotificationPanelViewController.setBar(mPanelBar);
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 c1d51f3..25af584 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
@@ -46,6 +46,7 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
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.tuner.TunerService;
import com.android.systemui.util.InjectionInflationController;
@@ -85,6 +86,7 @@
@Mock private NotificationShadeDepthController mNotificationShadeDepthController;
@Mock private SuperStatusBarViewFactory mStatusBarViewFactory;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
+ @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
@Before
public void setUp() {
@@ -123,11 +125,11 @@
mNotificationShadeDepthController,
mView,
mNotificationPanelViewController,
- mStatusBarViewFactory);
+ mStatusBarViewFactory,
+ mNotificationStackScrollLayoutController);
mController.setupExpandedStatusBar();
mController.setService(mStatusBar, mNotificationShadeWindowController);
mController.setDragDownHelper(mDragDownHelper);
-
}
@Test
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index 070626be..c70dfcc 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -256,6 +256,7 @@
return actionMasked;
}
}
+
/**
* Sends down events to the view hierarchy for all pointers which are not already being
* delivered i.e. pointers that are not yet injected.
@@ -285,6 +286,74 @@
}
/**
+ * Sends down events to the view hierarchy for all pointers which are not already being
+ * delivered with original down location. i.e. pointers that are not yet injected.
+ *
+ * @param prototype The prototype from which to create the injected events.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ void sendDownForAllNotInjectedPointersWithOriginalDown(MotionEvent prototype, int policyFlags) {
+ // Inject the injected pointers.
+ int pointerIdBits = 0;
+ final int pointerCount = prototype.getPointerCount();
+ final MotionEvent event = computeEventWithOriginalDown(prototype);
+ for (int i = 0; i < pointerCount; i++) {
+ final int pointerId = prototype.getPointerId(i);
+ // Do not send event for already delivered pointers.
+ if (!mState.isInjectedPointerDown(pointerId)) {
+ pointerIdBits |= (1 << pointerId);
+ final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i);
+ sendMotionEvent(
+ event,
+ action,
+ mState.getLastReceivedEvent(),
+ pointerIdBits,
+ policyFlags);
+ }
+ }
+ }
+
+ private MotionEvent computeEventWithOriginalDown(MotionEvent prototype) {
+ final int pointerCount = prototype.getPointerCount();
+ if (pointerCount != mState.getReceivedPointerTracker().getReceivedPointerDownCount()) {
+ Slog.w(LOG_TAG, "The pointer count doesn't match the received count.");
+ return MotionEvent.obtain(prototype);
+ }
+ MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[pointerCount];
+ MotionEvent.PointerProperties[] properties =
+ new MotionEvent.PointerProperties[pointerCount];
+ for (int i = 0; i < pointerCount; ++i) {
+ final int pointerId = prototype.getPointerId(i);
+ final float x = mState.getReceivedPointerTracker().getReceivedPointerDownX(pointerId);
+ final float y = mState.getReceivedPointerTracker().getReceivedPointerDownY(pointerId);
+ coords[i] = new MotionEvent.PointerCoords();
+ coords[i].x = x;
+ coords[i].y = y;
+ properties[i] = new MotionEvent.PointerProperties();
+ properties[i].id = pointerId;
+ properties[i].toolType = MotionEvent.TOOL_TYPE_FINGER;
+ }
+ MotionEvent event =
+ MotionEvent.obtain(
+ prototype.getDownTime(),
+ prototype.getEventTime(),
+ prototype.getAction(),
+ pointerCount,
+ properties,
+ coords,
+ prototype.getMetaState(),
+ prototype.getButtonState(),
+ prototype.getXPrecision(),
+ prototype.getYPrecision(),
+ prototype.getDeviceId(),
+ prototype.getEdgeFlags(),
+ prototype.getSource(),
+ prototype.getFlags());
+ return event;
+ }
+
+ /**
+ *
* Sends up events to the view hierarchy for all pointers which are already being delivered i.e.
* pointers that are injected.
*
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
index 07e8211..5b46cb4 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
@@ -294,7 +294,7 @@
+ Float.toString(mGestureDetectionThresholdPixels));
}
if (getState() == STATE_CLEAR) {
- if (moveDelta < mTouchSlop) {
+ if (moveDelta < (mTargetFingerCount * mTouchSlop)) {
// This still counts as a touch not a swipe.
continue;
} else if (mStrokeBuffers[pointerIndex].size() == 0) {
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 d127172..8305be3 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -608,7 +608,7 @@
mReceivedPointerTracker.getReceivedPointerDownY(id)
- rawEvent.getY(index);
final double moveDelta = Math.hypot(deltaX, deltaY);
- if (moveDelta < mTouchSlop) {
+ if (moveDelta < (2 * mTouchSlop)) {
return;
}
}
@@ -644,23 +644,20 @@
if (mGestureDetector.isMultiFingerGesturesEnabled()) {
if (mGestureDetector.isTwoFingerPassthroughEnabled()) {
if (event.getPointerCount() == 3) {
- boolean isOnBottomEdge = true;
// If three fingers went down on the bottom edge of the screen, delegate
// immediately.
- final long screenHeight =
- mContext.getResources().getDisplayMetrics().heightPixels;
- for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) {
- if (mReceivedPointerTracker.getReceivedPointerDownY(i)
- < (screenHeight - mEdgeSwipeHeightPixels)) {
- isOnBottomEdge = false;
- }
- }
- if (isOnBottomEdge) {
+ if (allPointersDownOnBottomEdge(event)) {
if (DEBUG) {
Slog.d(LOG_TAG, "Three-finger edge swipe detected.");
}
mState.startDelegating();
- mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
+ if (mState.isTouchExploring()) {
+ mDispatcher.sendDownForAllNotInjectedPointers(event,
+ policyFlags);
+ } else {
+ mDispatcher.sendDownForAllNotInjectedPointersWithOriginalDown(
+ event, policyFlags);
+ }
}
}
}
@@ -1063,6 +1060,22 @@
return downEvent;
}
+ private boolean allPointersDownOnBottomEdge(MotionEvent event) {
+ final long screenHeight =
+ mContext.getResources().getDisplayMetrics().heightPixels;
+ for (int i = 0; i < event.getPointerCount(); ++i) {
+ final int pointerId = event.getPointerId(i);
+ final float pointerDownY = mReceivedPointerTracker.getReceivedPointerDownY(pointerId);
+ if (pointerDownY < (screenHeight - mEdgeSwipeHeightPixels)) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "The pointer is not on the bottom edge" + pointerDownY);
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
public TouchState getState() {
return mState;
}
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 3ee5b28..7d6067c 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -176,7 +176,7 @@
Slog.i(LOG_TAG, "onDestroy(); delayed = "
+ mDetectingState.toString());
}
- mWindowMagnificationMgr.disableWindowMagnifier(mDisplayId, true);
+ mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
resetToDetectState();
}
@@ -211,14 +211,14 @@
final float scale = MathUtils.constrain(
mWindowMagnificationMgr.getPersistedScale(),
MIN_SCALE, MAX_SCALE);
- mWindowMagnificationMgr.enableWindowMagnifier(mDisplayId, scale, centerX, centerY);
+ mWindowMagnificationMgr.enableWindowMagnification(mDisplayId, scale, centerX, centerY);
}
private void disableWindowMagnifier() {
if (DEBUG_ALL) {
Slog.i(LOG_TAG, "disableWindowMagnifier()");
}
- mWindowMagnificationMgr.disableWindowMagnifier(mDisplayId, false);
+ mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, false);
}
private void toggleMagnification(float centerX, float centerY) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index ed2b26f..ecbece6 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -73,7 +73,7 @@
public void onReceive(Context context, Intent intent) {
final int displayId = context.getDisplayId();
removeMagnificationButton(displayId);
- disableWindowMagnification(displayId);
+ disableWindowMagnification(displayId, false);
}
};
@@ -136,10 +136,10 @@
/**
* Requests {@link IWindowMagnificationConnection} through
* {@link StatusBarManagerInternal#requestWindowMagnificationConnection(boolean)} and
- * destroys all window magnifiers if necessary.
+ * destroys all window magnifications if necessary.
*
* @param connect {@code true} if needs connection, otherwise set the connection to null and
- * destroy all window magnifiers.
+ * destroy all window magnifications.
* @return {@code true} if {@link IWindowMagnificationConnection} state is going to change.
*/
public boolean requestConnection(boolean connect) {
@@ -171,7 +171,7 @@
private void disableAllWindowMagnifiers() {
for (int i = 0; i < mWindowMagnifiers.size(); i++) {
final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i);
- magnifier.disable();
+ magnifier.disableWindowMagnificationInternal();
}
mWindowMagnifiers.clear();
}
@@ -187,12 +187,12 @@
@Override
public boolean processScroll(int displayId, float distanceX, float distanceY) {
- moveWindowMagnifier(displayId, -distanceX, -distanceY);
+ moveWindowMagnification(displayId, -distanceX, -distanceY);
return /* event consumed: */ true;
}
/**
- * Scales the magnified region on the specified display if the window magnifier is enabled.
+ * Scales the magnified region on the specified display if the window magnifier is initiated.
*
* @param displayId The logical display id.
* @param scale The target scale, must be >= 1
@@ -209,7 +209,7 @@
}
/**
- * Enables the window magnifier with specified center and scale on the specified display.
+ * Enables window magnification with specified center and scale on the specified display.
* @param displayId The logical display id.
* @param scale The target scale, must be >= 1.
* @param centerX The screen-relative X coordinate around which to center,
@@ -217,29 +217,29 @@
* @param centerY The screen-relative Y coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
*/
- void enableWindowMagnifier(int displayId, float scale, float centerX, float centerY) {
+ void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
magnifier = createWindowMagnifier(displayId);
}
- magnifier.enable(scale, centerX, centerY);
+ magnifier.enableWindowMagnificationInternal(scale, centerX, centerY);
}
}
/**
- * Disables the window magnifier on the specified display.
+ * Disables window magnification on the specified display.
*
* @param displayId The logical display id.
* @param clear {@true} Clears the state of the window magnifier
*/
- void disableWindowMagnifier(int displayId, boolean clear) {
+ void disableWindowMagnification(int displayId, boolean clear) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
return;
}
- magnifier.disable();
+ magnifier.disableWindowMagnificationInternal();
if (clear) {
mWindowMagnifiers.delete(displayId);
}
@@ -264,10 +264,10 @@
}
/**
- * Indicates whether this window magnifier is enabled on specified display.
+ * Indicates whether window magnification is enabled on specified display.
*
* @param displayId The logical display id.
- * @return {@code true} if the window magnifier is enabled.
+ * @return {@code true} if the window magnification is enabled.
*/
boolean isWindowMagnifierEnabled(int displayId) {
synchronized (mLock) {
@@ -323,7 +323,7 @@
}
/**
- * Moves the window magnifier with specified offset.
+ * Moves window magnification on the specified display with the specified offset.
*
* @param displayId The logical display id.
* @param offsetX the amount in pixels to offset the region in the X direction, in current
@@ -331,7 +331,7 @@
* @param offsetY the amount in pixels to offset the region in the Y direction, in current
* screen pixels.
*/
- void moveWindowMagnifier(int displayId, float offsetX, float offsetY) {
+ void moveWindowMagnification(int displayId, float offsetX, float offsetY) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
@@ -425,7 +425,8 @@
}
/**
- * A class to manipulate the window magnifier and contains the relevant information.
+ * A class manipulates window magnification per display and contains the magnification
+ * information.
*/
private static class WindowMagnifier {
@@ -434,7 +435,7 @@
private boolean mEnabled;
private final WindowMagnificationManager mWindowMagnificationManager;
- //Records the bounds of window magnifier.
+ //Records the bounds of window magnification.
private final Rect mBounds = new Rect();
//The magnified bounds on the screen.
private final Rect mSourceBounds = new Rect();
@@ -444,12 +445,12 @@
}
@GuardedBy("mLock")
- void enable(float scale, float centerX, float centerY) {
+ void enableWindowMagnificationInternal(float scale, float centerX, float centerY) {
if (mEnabled) {
return;
}
final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
- if (mWindowMagnificationManager.enableWindowMagnification(mDisplayId, normScale,
+ if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale,
centerX, centerY)) {
mScale = normScale;
mEnabled = true;
@@ -457,8 +458,9 @@
}
@GuardedBy("mLock")
- void disable() {
- if (mEnabled && mWindowMagnificationManager.disableWindowMagnification(mDisplayId)) {
+ void disableWindowMagnificationInternal() {
+ if (mEnabled && mWindowMagnificationManager.disableWindowMagnificationInternal(
+ mDisplayId)) {
mEnabled = false;
}
}
@@ -519,7 +521,7 @@
}
}
- private boolean enableWindowMagnification(int displayId, float scale, float centerX,
+ private boolean enableWindowMagnificationInternal(int displayId, float scale, float centerX,
float centerY) {
return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification(
displayId, scale, centerX, centerY);
@@ -529,7 +531,7 @@
return mConnectionWrapper != null && mConnectionWrapper.setScale(displayId, scale);
}
- private boolean disableWindowMagnification(int displayId) {
+ private boolean disableWindowMagnificationInternal(int displayId) {
return mConnectionWrapper != null && mConnectionWrapper.disableWindowMagnification(
displayId);
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 06ef58f..5447605 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -500,8 +500,8 @@
sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType);
}
- /*package*/ void postSetModeOwnerPid(int pid) {
- sendIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid);
+ /*package*/ void postSetModeOwnerPid(int pid, int mode) {
+ sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode);
}
/*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
@@ -977,7 +977,9 @@
synchronized (mDeviceStateLock) {
if (mModeOwnerPid != msg.arg1) {
mModeOwnerPid = msg.arg1;
- updateSpeakerphoneOn("setNewModeOwner");
+ if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
+ updateSpeakerphoneOn("setNewModeOwner");
+ }
if (mModeOwnerPid != 0) {
mBtHelper.disconnectBluetoothSco(mModeOwnerPid);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 673ca1f..3f29eb5 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3747,13 +3747,15 @@
private final IBinder mCb; // To be notified of client's death
private final int mPid;
private final int mUid;
- private String mPackage;
+ private final boolean mIsPrivileged;
+ private final String mPackage;
private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
- SetModeDeathHandler(IBinder cb, int pid, int uid, String caller) {
+ SetModeDeathHandler(IBinder cb, int pid, int uid, boolean isPrivileged, String caller) {
mCb = cb;
mPid = pid;
mUid = uid;
+ mIsPrivileged = isPrivileged;
mPackage = caller;
}
@@ -3765,12 +3767,13 @@
if (index < 0) {
Log.w(TAG, "unregistered setMode() client died");
} else {
- newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, mUid, TAG);
+ newModeOwnerPid = setModeInt(
+ AudioSystem.MODE_NORMAL, mCb, mPid, mUid, mIsPrivileged, TAG);
}
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid);
+ mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, AudioService.this.getMode());
}
public int getPid() {
@@ -3796,6 +3799,10 @@
public String getPackage() {
return mPackage;
}
+
+ public boolean isPrivileged() {
+ return mIsPrivileged;
+ }
}
/** @see AudioManager#setMode(int) */
@@ -3847,18 +3854,19 @@
+ " without permission or being mode owner");
return;
}
- newModeOwnerPid = setModeInt(
- mode, cb, callingPid, Binder.getCallingUid(), callingPackage);
+ newModeOwnerPid = setModeInt(mode, cb, callingPid, Binder.getCallingUid(),
+ hasModifyPhoneStatePermission, callingPackage);
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid);
+ mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, getMode());
}
// setModeInt() returns a valid PID if the audio mode was successfully set to
// any mode other than NORMAL.
@GuardedBy("mDeviceBroker.mSetModeLock")
- private int setModeInt(int mode, IBinder cb, int pid, int uid, String caller) {
+ private int setModeInt(
+ int mode, IBinder cb, int pid, int uid, boolean isPrivileged, String caller) {
if (DEBUG_MODE) {
Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid
+ ", uid=" + uid + ", caller=" + caller + ")");
@@ -3910,7 +3918,7 @@
}
} else {
if (hdlr == null) {
- hdlr = new SetModeDeathHandler(cb, pid, uid, caller);
+ hdlr = new SetModeDeathHandler(cb, pid, uid, isPrivileged, caller);
}
// Register for client death notification
try {
@@ -3969,7 +3977,8 @@
// change of mode may require volume to be re-applied on some devices
updateAbsVolumeMultiModeDevices(oldMode, actualMode);
- if (actualMode == AudioSystem.MODE_IN_COMMUNICATION) {
+ if (actualMode == AudioSystem.MODE_IN_COMMUNICATION
+ && !hdlr.isPrivileged()) {
sendMsg(mAudioHandler,
MSG_CHECK_MODE_FOR_UID,
SENDMSG_QUEUE,
@@ -6519,8 +6528,8 @@
CHECK_MODE_FOR_UID_PERIOD_MS);
break;
}
- // For now just log the fact that an app is hogging the audio mode.
- // TODO(b/160260850): remove abusive app from audio mode stack.
+ setModeInt(AudioSystem.MODE_NORMAL, h.getBinder(), h.getPid(), h.getUid(),
+ h.isPrivileged(), "MSG_CHECK_MODE_FOR_UID");
mModeLogger.log(new PhoneStateEvent(h.getPackage(), h.getPid()));
}
break;
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index a75a80a..4c63eb4 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -174,7 +174,7 @@
netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
}
- List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
+ List<UserInfo> users = mUserManager.getAliveUsers();
if (users != null) {
for (UserInfo user : users) {
mUsers.add(user.id);
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 5484bfc..7175489 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1463,7 +1463,7 @@
final long token = Binder.clearCallingIdentity();
List<UserInfo> users;
try {
- users = UserManager.get(mContext).getUsers(true);
+ users = UserManager.get(mContext).getAliveUsers();
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/inputmethod/TEST_MAPPING b/services/core/java/com/android/server/inputmethod/TEST_MAPPING
new file mode 100644
index 0000000..0ccd75d
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/core/java/android/view/inputmethod"
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 71f1833..534533f 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -1133,9 +1133,7 @@
return;
}
- String dumpFilter = args.length == 0 ? null : args[0];
-
- ipw.println("Location Manager State:");
+ ipw.print("Location Manager State:");
ipw.increaseIndent();
ipw.println("Elapsed Realtime: " + TimeUtils.formatDuration(SystemClock.elapsedRealtime()));
@@ -1166,34 +1164,28 @@
ipw.println(
"Location Controller Extra Package: " + mExtraLocationControllerPackage
+ (mExtraLocationControllerPackageEnabled ? " [enabled]"
- : "[disabled]"));
+ : " [disabled]"));
}
}
ipw.println("Location Providers:");
ipw.increaseIndent();
for (LocationProviderManager manager : mProviderManagers) {
- if (dumpFilter == null || manager.getName().equals(dumpFilter)) {
- manager.dump(fd, ipw, args);
- }
+ manager.dump(fd, ipw, args);
}
ipw.decreaseIndent();
- if (dumpFilter == null || GPS_PROVIDER.equals(dumpFilter)) {
- if (mGnssManagerService != null) {
- ipw.println("GNSS Manager:");
- ipw.increaseIndent();
- mGnssManagerService.dump(fd, ipw, args);
- ipw.decreaseIndent();
- }
- }
-
- if (dumpFilter == null || "geofence".equals(dumpFilter)) {
- ipw.println("Geofence Manager:");
+ if (mGnssManagerService != null) {
+ ipw.println("GNSS Manager:");
ipw.increaseIndent();
- mGeofenceManager.dump(fd, ipw, args);
+ mGnssManagerService.dump(fd, ipw, args);
ipw.decreaseIndent();
}
+
+ ipw.println("Geofence Manager:");
+ ipw.increaseIndent();
+ mGeofenceManager.dump(fd, ipw, args);
+ ipw.decreaseIndent();
}
private class LocalService extends LocationManagerInternal {
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index 06105bf..66245a2 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -84,7 +84,7 @@
import com.android.server.PendingIntentUtils;
import com.android.server.location.LocationPermissions.PermissionLevel;
import com.android.server.location.listeners.ListenerMultiplexer;
-import com.android.server.location.listeners.RemovableListenerRegistration;
+import com.android.server.location.listeners.RemoteListenerRegistration;
import com.android.server.location.util.AppForegroundHelper;
import com.android.server.location.util.AppForegroundHelper.AppForegroundListener;
import com.android.server.location.util.AppOpsHelper;
@@ -154,15 +154,8 @@
@Override
public void deliverOnLocationChanged(Location location,
- @Nullable Runnable onCompleteCallback)
- throws RemoteException {
- mListener.onLocationChanged(location,
- onCompleteCallback == null ? null : new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) {
- onCompleteCallback.run();
- }
- });
+ @Nullable Runnable onCompleteCallback) throws RemoteException {
+ mListener.onLocationChanged(location, SingleUseCallback.wrap(onCompleteCallback));
}
@Override
@@ -221,7 +214,7 @@
}
protected abstract class Registration extends
- RemovableListenerRegistration<LocationRequest, LocationTransport> {
+ RemoteListenerRegistration<LocationRequest, LocationTransport> {
@PermissionLevel protected final int mPermissionLevel;
private final WorkSource mWorkSource;
@@ -306,11 +299,12 @@
}
@Override
- protected final void onInactive() {
+ protected final ListenerOperation<LocationTransport> onInactive() {
onHighPowerUsageChanged();
if (!getRequest().getHideFromAppOps()) {
mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
}
+ return null;
}
@Override
@@ -826,6 +820,12 @@
@GuardedBy("mLock")
@Override
protected void onProviderListenerRegister() {
+ try {
+ ((IBinder) getKey()).linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ remove();
+ }
+
mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
SystemClock.elapsedRealtime());
@@ -837,12 +837,6 @@
0, this, FgThread.getHandler(), getWorkSource());
}
- try {
- ((IBinder) getKey()).linkToDeath(this, 0);
- } catch (RemoteException e) {
- remove();
- }
-
// start listening for provider enabled/disabled events
addEnabledListener(this);
@@ -1066,8 +1060,13 @@
mUserInfoHelper.addListener(mUserChangedListener);
mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
- // initialize enabled state
- onUserStarted(UserHandle.USER_ALL);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ // initialize enabled state
+ onUserStarted(UserHandle.USER_ALL);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1077,10 +1076,15 @@
mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
// notify and remove all listeners
- onUserStopped(UserHandle.USER_ALL);
- removeRegistrationIf(key -> true);
- mEnabledListeners.clear();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ onUserStopped(UserHandle.USER_ALL);
+ removeRegistrationIf(key -> true);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ mEnabledListeners.clear();
mStarted = false;
}
}
@@ -1141,14 +1145,26 @@
public void setRealProvider(AbstractLocationProvider provider) {
synchronized (mLock) {
Preconditions.checkState(mStarted);
- mProvider.setRealProvider(provider);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.setRealProvider(provider);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
public void setMockProvider(@Nullable MockProvider provider) {
synchronized (mLock) {
Preconditions.checkState(mStarted);
- mProvider.setMockProvider(provider);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.setMockProvider(provider);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
// when removing a mock provider, also clear any mock last locations and reset the
// location fudger. the mock provider could have been used to infer the current
@@ -1170,7 +1186,12 @@
throw new IllegalArgumentException(mName + " provider is not a test provider");
}
- mProvider.setMockProviderAllowed(enabled);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.setMockProviderAllowed(enabled);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1180,15 +1201,20 @@
throw new IllegalArgumentException(mName + " provider is not a test provider");
}
- String locationProvider = location.getProvider();
- if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
- // The location has an explicit provider that is different from the mock
- // provider name. The caller may be trying to fool us via b/33091107.
- EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
- mName + "!=" + locationProvider);
- }
+ long identity = Binder.clearCallingIdentity();
+ try {
+ String locationProvider = location.getProvider();
+ if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
+ // The location has an explicit provider that is different from the mock
+ // provider name. The caller may be trying to fool us via b/33091107.
+ EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
+ mName + "!=" + locationProvider);
+ }
- mProvider.setMockProviderLocation(location);
+ mProvider.setMockProviderLocation(location);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1279,7 +1305,7 @@
}
}
- public void getCurrentLocation(LocationRequest request, CallerIdentity identity,
+ public void getCurrentLocation(LocationRequest request, CallerIdentity callerIdentity,
int permissionLevel, ICancellationSignal cancellationTransport,
ILocationCallback callback) {
Preconditions.checkArgument(mName.equals(request.getProvider()));
@@ -1291,12 +1317,12 @@
GetCurrentLocationListenerRegistration registration =
new GetCurrentLocationListenerRegistration(
request,
- identity,
+ callerIdentity,
new GetCurrentLocationTransport(callback),
permissionLevel);
synchronized (mLock) {
- Location lastLocation = getLastLocation(request, identity, permissionLevel);
+ Location lastLocation = getLastLocation(request, callerIdentity, permissionLevel);
if (lastLocation != null) {
long locationAgeMs = NANOSECONDS.toMillis(
SystemClock.elapsedRealtimeNanos()
@@ -1314,7 +1340,13 @@
}
// if last location isn't good enough then we add a location request
- addRegistration(callback.asBinder(), registration);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(callback.asBinder(), registration);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
cancellationTransport);
if (cancellationSignal != null) {
@@ -1329,48 +1361,73 @@
}
public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
- mProvider.sendExtraCommand(uid, pid, command, extras);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.sendExtraCommand(uid, pid, command, extras);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
- public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+ public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@PermissionLevel int permissionLevel, ILocationListener listener) {
Preconditions.checkArgument(mName.equals(request.getProvider()));
synchronized (mLock) {
- addRegistration(
- listener.asBinder(),
- new LocationListenerRegistration(
- request,
- identity,
- new LocationListenerTransport(listener),
- permissionLevel));
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(
+ listener.asBinder(),
+ new LocationListenerRegistration(
+ request,
+ callerIdentity,
+ new LocationListenerTransport(listener),
+ permissionLevel));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
- public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+ public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@PermissionLevel int permissionLevel, PendingIntent pendingIntent) {
Preconditions.checkArgument(mName.equals(request.getProvider()));
synchronized (mLock) {
- addRegistration(
- pendingIntent,
- new LocationPendingIntentRegistration(
- request,
- identity,
- new LocationPendingIntentTransport(mContext, pendingIntent),
- permissionLevel));
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(
+ pendingIntent,
+ new LocationPendingIntentRegistration(
+ request,
+ callerIdentity,
+ new LocationPendingIntentTransport(mContext, pendingIntent),
+ permissionLevel));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
public void unregisterLocationRequest(ILocationListener listener) {
synchronized (mLock) {
- removeRegistration(listener.asBinder());
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistration(listener.asBinder());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
public void unregisterLocationRequest(PendingIntent pendingIntent) {
synchronized (mLock) {
- removeRegistration(pendingIntent);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistration(pendingIntent);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1958,4 +2015,50 @@
}
}
}
+
+ private static class SingleUseCallback extends IRemoteCallback.Stub {
+
+ @Nullable
+ public static IRemoteCallback wrap(@Nullable Runnable callback) {
+ return callback == null ? null : new SingleUseCallback(callback);
+ }
+
+ @GuardedBy("this")
+ @Nullable private Runnable mCallback;
+
+ private SingleUseCallback(Runnable callback) {
+ mCallback = Objects.requireNonNull(callback);
+ }
+
+ @Override
+ public void sendResult(Bundle data) {
+ Runnable callback;
+ synchronized (this) {
+ callback = mCallback;
+ mCallback = null;
+ }
+
+ // prevent this callback from being run more than once - otherwise this could provide an
+ // attack vector for a malicious app to break assumptions on how many times a callback
+ // may be invoked, and thus crash system server.
+ if (callback == null) {
+ return;
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ callback.run();
+ } catch (RuntimeException e) {
+ // since this is within a oneway binder transaction there is nowhere
+ // for exceptions to go - move onto another thread to crash system
+ // server so we find out about it
+ FgThread.getExecutor().execute(() -> {
+ throw new AssertionError(e);
+ });
+ throw e;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
index 2d9734e..2d7f028 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
@@ -32,6 +32,7 @@
import android.location.LocationManager;
import android.location.LocationRequest;
import android.location.util.identity.CallerIdentity;
+import android.os.Binder;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.WorkSource;
@@ -291,17 +292,28 @@
@Nullable String attributionTag) {
LocationPermissions.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_FINE);
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
- AppOpsManager.toReceiverId(pendingIntent));
- addRegistration(new GeofenceKey(pendingIntent, geofence),
- new GeofenceRegistration(geofence, identity, pendingIntent));
+ CallerIdentity callerIdentity = CallerIdentity.fromBinder(mContext, packageName,
+ attributionTag, AppOpsManager.toReceiverId(pendingIntent));
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(new GeofenceKey(pendingIntent, geofence),
+ new GeofenceRegistration(geofence, callerIdentity, pendingIntent));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
* Removes the geofence associated with the PendingIntent.
*/
public void removeGeofence(PendingIntent pendingIntent) {
- removeRegistrationIf(key -> key.getPendingIntent().equals(pendingIntent));
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistrationIf(key -> key.getPendingIntent().equals(pendingIntent));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 1b599b0..a9fdacc 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -25,6 +25,7 @@
import android.location.LocationManagerInternal;
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.util.identity.CallerIdentity;
+import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Process;
@@ -218,16 +219,27 @@
/**
* Adds a listener with the given identity and request.
*/
- protected void addListener(TRequest request, CallerIdentity identity, TListener listener) {
- addRegistration(listener.asBinder(),
- new GnssListenerRegistration(request, identity, listener));
+ protected void addListener(TRequest request, CallerIdentity callerIdentity,
+ TListener listener) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(listener.asBinder(),
+ new GnssListenerRegistration(request, callerIdentity, listener));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
* Removes the given listener.
*/
public void removeListener(TListener listener) {
- removeRegistration(listener.asBinder());
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistration(listener.asBinder());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
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 850cf7f..5c30fe8 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -2022,6 +2022,21 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ boolean dumpAll = false;
+
+ int opti = 0;
+ while (opti < args.length) {
+ String opt = args[opti];
+ if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
+ break;
+ }
+ opti++;
+ if ("-a".equals(opt)) {
+ dumpAll = true;
+ break;
+ }
+ }
+
StringBuilder s = new StringBuilder();
s.append("mStarted=").append(mStarted).append(" (changed ");
TimeUtils.formatDuration(SystemClock.elapsedRealtime()
@@ -2053,9 +2068,11 @@
s.append("]\n");
}
s.append(mGnssMetrics.dumpGnssMetricsAsText());
- s.append("native internal state: \n");
- s.append(" ").append(native_get_internal_state());
- s.append("\n");
+ if (dumpAll) {
+ s.append("native internal state: \n");
+ s.append(" ").append(native_get_internal_state());
+ s.append("\n");
+ }
pw.append(s);
}
diff --git a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
index bd8bce8..58aabda 100644
--- a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
@@ -32,10 +32,10 @@
* @param <TListener> listener type
*/
public abstract class BinderListenerRegistration<TRequest, TListener> extends
- RemovableListenerRegistration<TRequest, TListener> implements Binder.DeathRecipient {
+ RemoteListenerRegistration<TRequest, TListener> implements Binder.DeathRecipient {
/**
- * Interface to allowed binder retrieval when keys are not themselves IBinder.
+ * Interface to allow binder retrieval when keys are not themselves IBinders.
*/
public interface BinderKey {
/**
diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
index f94de9b..8a6b8aa 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
@@ -18,12 +18,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Binder;
import android.os.Build;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.IndentingPrintWriter;
-import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.listeners.ListenerExecutor.ListenerOperation;
@@ -31,8 +28,10 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -42,7 +41,7 @@
* divided into two categories, active registrations and inactive registrations, as defined by
* {@link #isActive(ListenerRegistration)}. If a registration's active state changes,
* {@link #updateRegistrations(Predicate)} must be invoked and return true for any registration
- * whose active state may have changed.
+ * whose active state may have changed. Listeners will only be invoked for active registrations.
*
* Callbacks invoked for various changes will always be ordered according to this lifecycle list:
*
@@ -64,14 +63,6 @@
* {@link #removeRegistration(Object, ListenerRegistration)}, not via any other removal method. This
* ensures re-entrant removal does not accidentally remove the incorrect registration.
*
- * All callbacks will be invoked with a cleared binder identity.
- *
- * Listeners owned by other processes will be run on a direct executor (and thus while holding a
- * lock). Listeners owned by the same process this multiplexer is in will be run asynchronously (and
- * thus without holding a lock). The underlying assumption is that listeners owned by other
- * processes will simply be forwarding the call to those other processes and perhaps performing
- * simple bookkeeping, with no potential for deadlock.
- *
* @param <TKey> key type
* @param <TRequest> request type
* @param <TListener> listener type
@@ -149,46 +140,51 @@
}
/**
- * Invoked before the first registration occurs. This is a convenient entry point for
- * registering listeners, etc, which only need to be present while there are any registrations.
+ * Invoked when the multiplexer goes from having no registrations to having some registrations.
+ * This is a convenient entry point for registering listeners, etc, which only need to be
+ * present while there are any registrations. Invoked while holding the multiplexer's internal
+ * lock.
*/
protected void onRegister() {}
/**
- * Invoked after the last unregistration occurs. This is a convenient entry point for
- * unregistering listeners, etc, which only need to be present while there are any
- * registrations.
+ * Invoked when the multiplexer goes from having some registrations to having no registrations.
+ * This is a convenient entry point for unregistering listeners, etc, which only need to be
+ * present while there are any registrations. Invoked while holding the multiplexer's internal
+ * lock.
*/
protected void onUnregister() {}
/**
- * Invoked when a registration is added.
+ * Invoked when a registration is added. Invoked while holding the multiplexer's internal lock.
*/
protected void onRegistrationAdded(@NonNull TKey key, @NonNull TRegistration registration) {}
/**
- * Invoked when a registration is removed.
+ * Invoked when a registration is removed. Invoked while holding the multiplexer's internal
+ * lock.
*/
protected void onRegistrationRemoved(@NonNull TKey key, @NonNull TRegistration registration) {}
/**
- * Invoked when the manager goes from having no active registrations to having some active
+ * Invoked when the multiplexer goes from having no active registrations to having some active
* registrations. This is a convenient entry point for registering listeners, etc, which only
- * need to be present while there are active registrations.
+ * need to be present while there are active registrations. Invoked while holding the
+ * multiplexer's internal lock.
*/
protected void onActive() {}
/**
- * Invoked when the manager goes from having some active registrations to having no active
+ * Invoked when the multiplexer goes from having some active registrations to having no active
* registrations. This is a convenient entry point for unregistering listeners, etc, which only
- * need to be present while there are active registrations.
+ * need to be present while there are active registrations. Invoked while holding the
+ * multiplexer's internal lock.
*/
protected void onInactive() {}
/**
- * Adds a new registration with the given key. Registration may fail if
- * {@link ListenerRegistration#onRegister(Object)} returns false, in which case the registration
- * will not be added. This method cannot be called to add a registration re-entrantly.
+ * Adds a new registration with the given key. This method cannot be called to add a
+ * registration re-entrantly.
*/
protected final void addRegistration(@NonNull TKey key, @NonNull TRegistration registration) {
Objects.requireNonNull(key);
@@ -204,7 +200,6 @@
// involve removing a prior registration. note that try-with-resources ordering is
// meaningful here as well. we want to close the reentrancy guard first, as this may
// generate additional service updates, then close the update service buffer.
- long identity = Binder.clearCallingIdentity();
try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {
@@ -224,16 +219,13 @@
registration.onRegister(key);
onRegistrationAdded(key, registration);
onRegistrationActiveChanged(registration);
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
/**
- * Removes the registration with the given key. If unregistration occurs,
- * {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This method
- * cannot be called to remove a registration re-entrantly.
+ * Removes the registration with the given key. This method cannot be called to remove a
+ * registration re-entrantly.
*/
protected final void removeRegistration(@NonNull Object key) {
synchronized (mRegistrations) {
@@ -250,9 +242,8 @@
}
/**
- * Removes all registrations with keys that satisfy the given predicate. If unregistration
- * occurs, {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This
- * method cannot be called to remove a registration re-entrantly.
+ * Removes all registrations with keys that satisfy the given predicate. This method cannot be
+ * called to remove a registration re-entrantly.
*/
protected final void removeRegistrationIf(@NonNull Predicate<TKey> predicate) {
synchronized (mRegistrations) {
@@ -281,11 +272,8 @@
/**
* Removes the given registration with the given key. If the given key has a different
- * registration at the time this method is called, nothing happens. If unregistration occurs,
- * {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This method
- * allows for re-entrancy, and may be called to remove a registration re-entrantly. In this case
- * the registration will immediately be marked inactive and unregistered, and will be removed
- * completely at some later time.
+ * registration at the time this method is called, nothing happens. This method allows for
+ * re-entrancy, and may be called to remove a registration re-entrantly.
*/
protected final void removeRegistration(@NonNull Object key,
@NonNull ListenerRegistration<?, ?> registration) {
@@ -324,7 +312,6 @@
// in multiple service updates. note that try-with-resources ordering is meaningful here as
// well. we want to close the reentrancy guard first, as this may generate additional
// service updates, then close the update service buffer.
- long identity = Binder.clearCallingIdentity();
try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {
@@ -337,8 +324,6 @@
onUnregister();
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
@@ -362,34 +347,42 @@
}
}
- long identity = Binder.clearCallingIdentity();
- try {
- if (actives.isEmpty()) {
+ if (actives.isEmpty()) {
+ mCurrentRequest = null;
+ if (mServiceRegistered) {
+ mServiceRegistered = false;
mCurrentRequest = null;
- if (mServiceRegistered) {
- mServiceRegistered = false;
- mCurrentRequest = null;
- unregisterWithService();
- }
- return;
+ unregisterWithService();
}
-
- TMergedRequest merged = mergeRequests(actives);
- if (!mServiceRegistered || !Objects.equals(merged, mCurrentRequest)) {
- if (mServiceRegistered) {
- mServiceRegistered = reregisterWithService(mCurrentRequest, merged);
- } else {
- mServiceRegistered = registerWithService(merged);
- }
- if (mServiceRegistered) {
- mCurrentRequest = merged;
- } else {
- mCurrentRequest = null;
- }
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
+ return;
}
+
+ TMergedRequest merged = mergeRequests(actives);
+ if (!mServiceRegistered || !Objects.equals(merged, mCurrentRequest)) {
+ if (mServiceRegistered) {
+ mServiceRegistered = reregisterWithService(mCurrentRequest, merged);
+ } else {
+ mServiceRegistered = registerWithService(merged);
+ }
+ if (mServiceRegistered) {
+ mCurrentRequest = merged;
+ } else {
+ mCurrentRequest = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Clears currently stored service state, and invokes {@link #updateService()} to force a new
+ * call to {@link #registerWithService(Object)} if necessary. This is useful, for instance, if
+ * the backing service has crashed or otherwise lost state, and needs to be re-initialized.
+ */
+ protected final void resetService() {
+ synchronized (mRegistrations) {
+ mServiceRegistered = false;
+ mCurrentRequest = null;
+ updateService();
}
}
@@ -404,9 +397,9 @@
/**
* Evaluates the predicate on all registrations. The predicate should return true if the active
- * state of the registration may have changed as a result. Any {@link #updateService()}
- * invocations made while this method is executing will be deferred until after the method is
- * complete so as to avoid redundant work.
+ * state of the registration may have changed as a result. If the active state of any
+ * registration has changed, {@link #updateService()} will automatically be invoked to handle
+ * the resulting changes.
*/
protected final void updateRegistrations(@NonNull Predicate<TRegistration> predicate) {
synchronized (mRegistrations) {
@@ -415,7 +408,6 @@
// callbacks. note that try-with-resources ordering is meaningful here as well. we want
// to close the reentrancy guard first, as this may generate additional service updates,
// then close the update service buffer.
- long identity = Binder.clearCallingIdentity();
try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {
@@ -426,8 +418,6 @@
onRegistrationActiveChanged(registration);
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
@@ -450,7 +440,10 @@
execute(registration, operation);
}
} else {
- registration.onInactive();
+ ListenerOperation<TListener> operation = registration.onInactive();
+ if (operation != null) {
+ execute(registration, operation);
+ }
if (--mActiveRegistrationsCount == 0) {
onInactive();
}
@@ -468,7 +461,6 @@
protected final void deliverToListeners(
@NonNull Function<TRegistration, ListenerOperation<TListener>> function) {
synchronized (mRegistrations) {
- long identity = Binder.clearCallingIdentity();
try (ReentrancyGuard ignored = mReentrancyGuard.acquire()) {
final int size = mRegistrations.size();
for (int i = 0; i < size; i++) {
@@ -480,8 +472,6 @@
}
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
@@ -495,7 +485,6 @@
*/
protected final void deliverToListeners(@NonNull ListenerOperation<TListener> operation) {
synchronized (mRegistrations) {
- long identity = Binder.clearCallingIdentity();
try (ReentrancyGuard ignored = mReentrancyGuard.acquire()) {
final int size = mRegistrations.size();
for (int i = 0; i < size; i++) {
@@ -504,8 +493,6 @@
execute(registration, operation);
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
@@ -522,27 +509,26 @@
/**
* Dumps debug information.
*/
- public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mRegistrations) {
- ipw.print("service: ");
- dumpServiceState(ipw);
- ipw.println();
+ pw.print("service: ");
+ dumpServiceState(pw);
+ pw.println();
if (!mRegistrations.isEmpty()) {
- ipw.println("listeners:");
+ pw.println("listeners:");
- ipw.increaseIndent();
final int size = mRegistrations.size();
for (int i = 0; i < size; i++) {
TRegistration registration = mRegistrations.valueAt(i);
- ipw.print(registration);
+ pw.print(" ");
+ pw.print(registration);
if (!registration.isActive()) {
- ipw.println(" (inactive)");
+ pw.println(" (inactive)");
} else {
- ipw.println();
+ pw.println();
}
}
- ipw.decreaseIndent();
}
}
}
@@ -577,7 +563,7 @@
@GuardedBy("mRegistrations")
private int mGuardCount;
@GuardedBy("mRegistrations")
- private @Nullable ArraySet<Pair<Object, ListenerRegistration<?, ?>>> mScheduledRemovals;
+ private @Nullable ArraySet<Entry<Object, ListenerRegistration<?, ?>>> mScheduledRemovals;
ReentrancyGuard() {
mGuardCount = 0;
@@ -602,7 +588,7 @@
if (mScheduledRemovals == null) {
mScheduledRemovals = new ArraySet<>(mRegistrations.size());
}
- mScheduledRemovals.add(new Pair<>(key, registration));
+ mScheduledRemovals.add(new AbstractMap.SimpleImmutableEntry<>(key, registration));
}
ReentrancyGuard acquire() {
@@ -612,7 +598,7 @@
@Override
public void close() {
- ArraySet<Pair<Object, ListenerRegistration<?, ?>>> scheduledRemovals = null;
+ ArraySet<Entry<Object, ListenerRegistration<?, ?>>> scheduledRemovals = null;
Preconditions.checkState(mGuardCount > 0);
if (--mGuardCount == 0) {
@@ -620,14 +606,15 @@
mScheduledRemovals = null;
}
- if (scheduledRemovals != null) {
- try (UpdateServiceBuffer ignored = mUpdateServiceBuffer.acquire()) {
- final int size = scheduledRemovals.size();
- for (int i = 0; i < size; i++) {
- Pair<Object, ListenerRegistration<?, ?>> pair = scheduledRemovals.valueAt(
- i);
- removeRegistration(pair.first, pair.second);
- }
+ if (scheduledRemovals == null) {
+ return;
+ }
+
+ try (UpdateServiceBuffer ignored = mUpdateServiceBuffer.acquire()) {
+ final int size = scheduledRemovals.size();
+ for (int i = 0; i < size; i++) {
+ Entry<Object, ListenerRegistration<?, ?>> entry = scheduledRemovals.valueAt(i);
+ removeRegistration(entry.getKey(), entry.getValue());
}
}
}
diff --git a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
index ac56c51..deb9660 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
@@ -17,55 +17,34 @@
package com.android.server.location.listeners;
-import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.location.util.identity.CallerIdentity;
-import android.os.Process;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.listeners.ListenerExecutor;
-import com.android.server.FgThread;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
* A listener registration object which holds data associated with the listener, such as an optional
- * request, and the identity of the listener owner.
+ * request, and an executor responsible for listener invocations.
*
* @param <TRequest> request type
* @param <TListener> listener type
*/
public class ListenerRegistration<TRequest, TListener> implements ListenerExecutor {
- @VisibleForTesting
- public static final Executor IN_PROCESS_EXECUTOR = FgThread.getExecutor();
-
private final Executor mExecutor;
private final @Nullable TRequest mRequest;
- private final CallerIdentity mIdentity;
private boolean mActive;
private volatile @Nullable TListener mListener;
- protected ListenerRegistration(@Nullable TRequest request, CallerIdentity identity,
+ protected ListenerRegistration(Executor executor, @Nullable TRequest request,
TListener listener) {
- // if a client is in the same process as us, binder calls will execute synchronously and
- // we shouldn't run callbacks directly since they might be run under lock and deadlock
- if (identity.getPid() == Process.myPid()) {
- // there's a slight loophole here for pending intents - pending intent callbacks can
- // always be run on the direct executor since they're always asynchronous, but honestly
- // you shouldn't be using pending intent callbacks within the same process anyways
- mExecutor = IN_PROCESS_EXECUTOR;
- } else {
- mExecutor = DIRECT_EXECUTOR;
- }
-
+ mExecutor = Objects.requireNonNull(executor);
mRequest = request;
- mIdentity = Objects.requireNonNull(identity);
mActive = false;
mListener = Objects.requireNonNull(listener);
}
@@ -82,34 +61,34 @@
}
/**
- * Returns the listener identity.
- */
- public final CallerIdentity getIdentity() {
- return mIdentity;
- }
-
- /**
- * May be overridden by subclasses. Invoked when registration occurs.
+ * May be overridden by subclasses. Invoked when registration occurs. Invoked while holding the
+ * owning multiplexer's internal lock.
*/
protected void onRegister(Object key) {}
/**
- * May be overridden by subclasses. Invoked when unregistration occurs.
+ * May be overridden by subclasses. Invoked when unregistration occurs. Invoked while holding
+ * the owning multiplexer's internal lock.
*/
protected void onUnregister() {}
/**
* May be overridden by subclasses. Invoked when this registration becomes active. If this
- * returns a non-null operation, that operation will be invoked for the listener.
+ * returns a non-null operation, that operation will be invoked for the listener. Invoked
+ * while holding the owning multiplexer's internal lock.
*/
protected @Nullable ListenerOperation<TListener> onActive() {
return null;
}
/**
- * May be overridden by subclasses. Invoked when registration becomes inactive.
+ * May be overridden by subclasses. Invoked when registration becomes inactive. If this returns
+ * a non-null operation, that operation will be invoked for the listener. Invoked while holding
+ * the owning multiplexer's internal lock.
*/
- protected void onInactive() {}
+ protected @Nullable ListenerOperation<TListener> onInactive() {
+ return null;
+ }
public final boolean isActive() {
return mActive;
@@ -136,8 +115,7 @@
/**
* May be overridden by subclasses, however should rarely be needed. Invoked when the listener
* associated with this registration is unregistered, which may occur before the registration
- * itself is unregistered. This immediately prevents the listener from being further invoked
- * even if the various bookkeeping associated with unregistration has not occurred yet.
+ * itself is unregistered. This immediately prevents the listener from being further invoked.
*/
protected void onListenerUnregister() {};
diff --git a/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java b/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java
index b5d2ef6..7b6154e 100644
--- a/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java
@@ -30,7 +30,7 @@
* @param <TListener> listener type
*/
public abstract class PendingIntentListenerRegistration<TRequest, TListener> extends
- RemovableListenerRegistration<TRequest, TListener> implements PendingIntent.CancelListener {
+ RemoteListenerRegistration<TRequest, TListener> implements PendingIntent.CancelListener {
/**
* Interface to allowed pending intent retrieval when keys are not themselves PendingIntents.
diff --git a/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java b/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java
new file mode 100644
index 0000000..e4b0b19
--- /dev/null
+++ b/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java
@@ -0,0 +1,75 @@
+/*
+ * 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.location.listeners;
+
+
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
+import android.annotation.Nullable;
+import android.location.util.identity.CallerIdentity;
+import android.os.Process;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.FgThread;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * A listener registration representing a remote (possibly from a different process) listener.
+ * Listeners from a different process will be run on a direct executor, since the x-process listener
+ * invocation should already be asynchronous. Listeners from the same process will be run on a
+ * normal executor, since in-process listener invocation may be synchronous.
+ *
+ * @param <TRequest> request type
+ * @param <TListener> listener type
+ */
+public abstract class RemoteListenerRegistration<TRequest, TListener> extends
+ RemovableListenerRegistration<TRequest, TListener> {
+
+ @VisibleForTesting
+ public static final Executor IN_PROCESS_EXECUTOR = FgThread.getExecutor();
+
+ private static Executor chooseExecutor(CallerIdentity identity) {
+ // if a client is in the same process as us, binder calls will execute synchronously and
+ // we shouldn't run callbacks directly since they might be run under lock and deadlock
+ if (identity.getPid() == Process.myPid()) {
+ // there's a slight loophole here for pending intents - pending intent callbacks can
+ // always be run on the direct executor since they're always asynchronous, but honestly
+ // you shouldn't be using pending intent callbacks within the same process anyways
+ return IN_PROCESS_EXECUTOR;
+ } else {
+ return DIRECT_EXECUTOR;
+ }
+ }
+
+ private final CallerIdentity mIdentity;
+
+ protected RemoteListenerRegistration(String tag, @Nullable TRequest request,
+ CallerIdentity identity, TListener listener) {
+ super(tag, chooseExecutor(identity), request, listener);
+ mIdentity = Objects.requireNonNull(identity);
+ }
+
+ /**
+ * Returns the listener identity.
+ */
+ public final CallerIdentity getIdentity() {
+ return mIdentity;
+ }
+}
+
diff --git a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
index 0698cca..2383bec 100644
--- a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
@@ -17,10 +17,10 @@
package com.android.server.location.listeners;
import android.annotation.Nullable;
-import android.location.util.identity.CallerIdentity;
import android.util.Log;
import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* A listener registration that stores its own key, and thus can remove itself. By default it will
@@ -36,9 +36,9 @@
private volatile @Nullable Object mKey;
- protected RemovableListenerRegistration(String tag, @Nullable TRequest request,
- CallerIdentity callerIdentity, TListener listener) {
- super(request, callerIdentity, listener);
+ protected RemovableListenerRegistration(String tag, Executor executor,
+ @Nullable TRequest request, TListener listener) {
+ super(executor, request, listener);
mTag = Objects.requireNonNull(tag);
}
@@ -70,7 +70,7 @@
@Override
public <Listener> void onOperationFailure(ListenerOperation<Listener> operation, Exception e) {
- Log.w(mTag, "registration " + getIdentity() + " removed due to unexpected exception", e);
+ Log.w(mTag, "registration " + this + " removed due to unexpected exception", e);
remove();
}
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
new file mode 100644
index 0000000..d8745ab
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -0,0 +1,310 @@
+/*
+ * 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.pm;
+
+import static android.content.pm.PackageManager.PARTIAL_MERKLE_ROOT_1M_SHA256;
+import static android.content.pm.PackageManager.PARTIAL_MERKLE_ROOT_1M_SHA512;
+import static android.content.pm.PackageManager.WHOLE_MD5;
+import static android.content.pm.PackageManager.WHOLE_MERKLE_ROOT_4K_SHA256;
+import static android.content.pm.PackageManager.WHOLE_SHA1;
+import static android.content.pm.PackageManager.WHOLE_SHA256;
+import static android.content.pm.PackageManager.WHOLE_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256;
+
+import android.annotation.Nullable;
+import android.content.pm.FileChecksum;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.util.apk.ApkSignatureSchemeV2Verifier;
+import android.util.apk.ApkSignatureSchemeV3Verifier;
+import android.util.apk.ApkSignatureSchemeV4Verifier;
+import android.util.apk.ApkSignatureVerifier;
+import android.util.apk.ApkSigningBlockUtils;
+import android.util.apk.ByteBufferFactory;
+import android.util.apk.SignatureInfo;
+import android.util.apk.SignatureNotFoundException;
+import android.util.apk.VerityBuilder;
+
+import com.android.server.security.VerityUtils;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides checksums for APK.
+ */
+public class ApkChecksums {
+ static final String TAG = "ApkChecksums";
+
+ // MessageDigest algorithms.
+ static final String ALGO_MD5 = "MD5";
+ static final String ALGO_SHA1 = "SHA1";
+ static final String ALGO_SHA256 = "SHA256";
+ static final String ALGO_SHA512 = "SHA512";
+
+ /**
+ * Fetch or calculate checksums for the specific file.
+ *
+ * @param split split name, null for base
+ * @param file to fetch checksums for
+ * @param optional mask to fetch readily available checksums
+ * @param required mask to forcefully calculate if not available
+ * @param trustedInstallers array of certificate to trust, two specific cases:
+ * null - trust anybody,
+ * [] - trust nobody.
+ */
+ public static List<FileChecksum> getFileChecksums(String split, File file,
+ @PackageManager.FileChecksumKind int optional,
+ @PackageManager.FileChecksumKind int required,
+ @Nullable Certificate[] trustedInstallers) {
+ final String filePath = file.getAbsolutePath();
+ Map<Integer, FileChecksum> checksums = new ArrayMap<>();
+ final int kinds = (optional | required);
+ // System enforced: FSI or v2/v3/v4 signatures.
+ if ((kinds & WHOLE_MERKLE_ROOT_4K_SHA256) != 0) {
+ // Hashes in fs-verity and IncFS are always verified.
+ FileChecksum checksum = extractHashFromFS(split, filePath);
+ if (checksum != null) {
+ checksums.put(checksum.getKind(), checksum);
+ }
+ }
+ if ((kinds & (PARTIAL_MERKLE_ROOT_1M_SHA256 | PARTIAL_MERKLE_ROOT_1M_SHA512)) != 0) {
+ Map<Integer, FileChecksum> v2v3checksums = extractHashFromV2V3Signature(
+ split, filePath, kinds);
+ if (v2v3checksums != null) {
+ checksums.putAll(v2v3checksums);
+ }
+ }
+
+ // TODO(b/160605420): Installer provided.
+ // TODO(b/160605420): Wait for Incremental to be fully loaded.
+
+ // Manually calculating required checksums if not readily available.
+ if ((required & WHOLE_MERKLE_ROOT_4K_SHA256) != 0 && !checksums.containsKey(
+ WHOLE_MERKLE_ROOT_4K_SHA256)) {
+ try {
+ byte[] generatedRootHash = VerityBuilder.generateFsVerityRootHash(
+ filePath, /*salt=*/null,
+ new ByteBufferFactory() {
+ @Override
+ public ByteBuffer create(int capacity) {
+ return ByteBuffer.allocate(capacity);
+ }
+ });
+ checksums.put(WHOLE_MERKLE_ROOT_4K_SHA256,
+ new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, generatedRootHash));
+ } catch (IOException | NoSuchAlgorithmException | DigestException e) {
+ Slog.e(TAG, "Error calculating WHOLE_MERKLE_ROOT_4K_SHA256", e);
+ }
+ }
+
+ calculateChecksumIfRequested(checksums, split, file, required, WHOLE_MD5);
+ calculateChecksumIfRequested(checksums, split, file, required, WHOLE_SHA1);
+ calculateChecksumIfRequested(checksums, split, file, required, WHOLE_SHA256);
+ calculateChecksumIfRequested(checksums, split, file, required, WHOLE_SHA512);
+
+ calculatePartialChecksumsIfRequested(checksums, split, file, required);
+
+ return new ArrayList<>(checksums.values());
+ }
+
+ private static FileChecksum extractHashFromFS(String split, String filePath) {
+ // verity first
+ {
+ byte[] hash = VerityUtils.getFsverityRootHash(filePath);
+ if (hash != null) {
+ return new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash);
+ }
+ }
+ // v4 next
+ try {
+ ApkSignatureSchemeV4Verifier.VerifiedSigner signer =
+ ApkSignatureSchemeV4Verifier.extractCertificates(filePath);
+ byte[] hash = signer.contentDigests.getOrDefault(CONTENT_DIGEST_VERITY_CHUNKED_SHA256,
+ null);
+ if (hash != null) {
+ return new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash);
+ }
+ } catch (SignatureNotFoundException e) {
+ // Nothing
+ } catch (SecurityException e) {
+ Slog.e(TAG, "V4 signature error", e);
+ }
+ return null;
+ }
+
+ private static Map<Integer, FileChecksum> extractHashFromV2V3Signature(
+ String split, String filePath, int kinds) {
+ Map<Integer, byte[]> contentDigests = null;
+ try {
+ contentDigests = ApkSignatureVerifier.verifySignaturesInternal(filePath,
+ PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2,
+ false).contentDigests;
+ } catch (PackageParser.PackageParserException e) {
+ Slog.e(TAG, "Signature verification error", e);
+ }
+
+ if (contentDigests == null) {
+ return null;
+ }
+
+ Map<Integer, FileChecksum> checksums = new ArrayMap<>();
+ if ((kinds & PARTIAL_MERKLE_ROOT_1M_SHA256) != 0) {
+ byte[] hash = contentDigests.getOrDefault(CONTENT_DIGEST_CHUNKED_SHA256, null);
+ if (hash != null) {
+ checksums.put(PARTIAL_MERKLE_ROOT_1M_SHA256,
+ new FileChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA256, hash));
+ }
+ }
+ if ((kinds & PARTIAL_MERKLE_ROOT_1M_SHA512) != 0) {
+ byte[] hash = contentDigests.getOrDefault(CONTENT_DIGEST_CHUNKED_SHA512, null);
+ if (hash != null) {
+ checksums.put(PARTIAL_MERKLE_ROOT_1M_SHA512,
+ new FileChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA512, hash));
+ }
+ }
+ return checksums;
+ }
+
+ private static String getMessageDigestAlgoForChecksumKind(int kind)
+ throws NoSuchAlgorithmException {
+ switch (kind) {
+ case WHOLE_MD5:
+ return ALGO_MD5;
+ case WHOLE_SHA1:
+ return ALGO_SHA1;
+ case WHOLE_SHA256:
+ return ALGO_SHA256;
+ case WHOLE_SHA512:
+ return ALGO_SHA512;
+ default:
+ throw new NoSuchAlgorithmException("Invalid checksum kind: " + kind);
+ }
+ }
+
+ private static void calculateChecksumIfRequested(Map<Integer, FileChecksum> checksums,
+ String split, File file, int required, int kind) {
+ if ((required & kind) != 0 && !checksums.containsKey(kind)) {
+ final byte[] checksum = getFileChecksum(file, kind);
+ if (checksum != null) {
+ checksums.put(kind, new FileChecksum(split, kind, checksum));
+ }
+ }
+ }
+
+ private static byte[] getFileChecksum(File file, int kind) {
+ try (FileInputStream fis = new FileInputStream(file);
+ BufferedInputStream bis = new BufferedInputStream(fis)) {
+ byte[] dataBytes = new byte[512 * 1024];
+ int nread = 0;
+
+ final String algo = getMessageDigestAlgoForChecksumKind(kind);
+ MessageDigest md = MessageDigest.getInstance(algo);
+ while ((nread = bis.read(dataBytes)) != -1) {
+ md.update(dataBytes, 0, nread);
+ }
+
+ return md.digest();
+ } catch (IOException e) {
+ Slog.e(TAG, "Error reading " + file.getAbsolutePath() + " to compute hash.", e);
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ Slog.e(TAG, "Device does not support MessageDigest algorithm", e);
+ return null;
+ }
+ }
+
+ private static int[] getContentDigestAlgos(boolean needSignatureSha256,
+ boolean needSignatureSha512) {
+ if (needSignatureSha256 && needSignatureSha512) {
+ // Signature block present, but no digests???
+ return new int[]{CONTENT_DIGEST_CHUNKED_SHA256, CONTENT_DIGEST_CHUNKED_SHA512};
+ } else if (needSignatureSha256) {
+ return new int[]{CONTENT_DIGEST_CHUNKED_SHA256};
+ } else {
+ return new int[]{CONTENT_DIGEST_CHUNKED_SHA512};
+ }
+ }
+
+ private static int getChecksumKindForContentDigestAlgo(int contentDigestAlgo) {
+ switch (contentDigestAlgo) {
+ case CONTENT_DIGEST_CHUNKED_SHA256:
+ return PARTIAL_MERKLE_ROOT_1M_SHA256;
+ case CONTENT_DIGEST_CHUNKED_SHA512:
+ return PARTIAL_MERKLE_ROOT_1M_SHA512;
+ default:
+ return -1;
+ }
+ }
+
+ private static void calculatePartialChecksumsIfRequested(Map<Integer, FileChecksum> checksums,
+ String split, File file, int required) {
+ boolean needSignatureSha256 =
+ (required & PARTIAL_MERKLE_ROOT_1M_SHA256) != 0 && !checksums.containsKey(
+ PARTIAL_MERKLE_ROOT_1M_SHA256);
+ boolean needSignatureSha512 =
+ (required & PARTIAL_MERKLE_ROOT_1M_SHA512) != 0 && !checksums.containsKey(
+ PARTIAL_MERKLE_ROOT_1M_SHA512);
+ if (!needSignatureSha256 && !needSignatureSha512) {
+ return;
+ }
+
+ try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
+ SignatureInfo signatureInfo = null;
+ try {
+ signatureInfo = ApkSignatureSchemeV3Verifier.findSignature(raf);
+ } catch (SignatureNotFoundException e) {
+ try {
+ signatureInfo = ApkSignatureSchemeV2Verifier.findSignature(raf);
+ } catch (SignatureNotFoundException ee) {
+ }
+ }
+ if (signatureInfo == null) {
+ Slog.e(TAG, "V2/V3 signatures not found in " + file.getAbsolutePath());
+ return;
+ }
+
+ final int[] digestAlgos = getContentDigestAlgos(needSignatureSha256,
+ needSignatureSha512);
+ byte[][] digests = ApkSigningBlockUtils.computeContentDigestsPer1MbChunk(digestAlgos,
+ raf.getFD(), signatureInfo);
+ for (int i = 0, size = digestAlgos.length; i < size; ++i) {
+ int checksumKind = getChecksumKindForContentDigestAlgo(digestAlgos[i]);
+ if (checksumKind != -1) {
+ checksums.put(checksumKind, new FileChecksum(split, checksumKind, digests[i]));
+ }
+ }
+ } catch (IOException | DigestException e) {
+ Slog.e(TAG, "Error computing hash.", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c05bc45..344f9cf 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -40,6 +40,7 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.EXTRA_CHECKSUMS;
import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -168,6 +169,7 @@
import android.content.pm.DataLoaderType;
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureInfo;
+import android.content.pm.FileChecksum;
import android.content.pm.IDexModuleRegisterCallback;
import android.content.pm.IPackageChangeObserver;
import android.content.pm.IPackageDataObserver;
@@ -254,6 +256,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
+import android.os.ParcelableException;
import android.os.PatternMatcher;
import android.os.PersistableBundle;
import android.os.Process;
@@ -394,6 +397,7 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -404,7 +408,10 @@
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -2400,9 +2407,12 @@
final int callingUserId = UserHandle.getUserId(callingUid);
for (String packageName : packages) {
- PackageSetting setting = mSettings.mPackages.get(packageName);
- if (setting != null
- && !shouldFilterApplicationLocked(setting, callingUid, callingUserId)) {
+ final boolean filterApp;
+ synchronized (mLock) {
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
+ filterApp = shouldFilterApplicationLocked(ps, callingUid, callingUserId);
+ }
+ if (!filterApp) {
notifyInstallObserver(packageName);
}
}
@@ -2443,6 +2453,83 @@
mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
}
+ @Override
+ public void getChecksums(@NonNull String packageName, boolean includeSplits,
+ @PackageManager.FileChecksumKind int optional,
+ @PackageManager.FileChecksumKind int required, @Nullable List trustedInstallers,
+ @NonNull IntentSender statusReceiver, int userId) {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(statusReceiver);
+
+ final ApplicationInfo applicationInfo = getApplicationInfoInternal(packageName, 0,
+ Binder.getCallingUid(), userId);
+ if (applicationInfo == null) {
+ throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
+ }
+
+ List<Pair<String, File>> filesToChecksum = new ArrayList<>();
+
+ // Adding base split.
+ filesToChecksum.add(Pair.create(null, new File(applicationInfo.sourceDir)));
+
+ // Adding other splits.
+ if (includeSplits && applicationInfo.splitNames != null) {
+ for (int i = 0, size = applicationInfo.splitNames.length; i < size; ++i) {
+ filesToChecksum.add(Pair.create(applicationInfo.splitNames[i],
+ new File(applicationInfo.splitSourceDirs[i])));
+ }
+ }
+
+ for (int i = 0, size = filesToChecksum.size(); i < size; ++i) {
+ final File file = filesToChecksum.get(i).second;
+ if (!file.exists()) {
+ throw new IllegalStateException("File not found: " + file.getPath());
+ }
+ }
+
+ final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates(
+ trustedInstallers) : null;
+ final Context context = mContext;
+
+ mInjector.getBackgroundExecutor().execute(() -> {
+ final Intent intent = new Intent();
+ List<FileChecksum> result = new ArrayList<>();
+ for (int i = 0, size = filesToChecksum.size(); i < size; ++i) {
+ final String split = filesToChecksum.get(i).first;
+ final File file = filesToChecksum.get(i).second;
+ try {
+ result.addAll(ApkChecksums.getFileChecksums(split, file, optional, required,
+ trustedCerts));
+ } catch (Throwable e) {
+ Slog.e(TAG, "Checksum calculation error", e);
+ }
+ }
+ intent.putExtra(EXTRA_CHECKSUMS,
+ result.toArray(new FileChecksum[result.size()]));
+
+ try {
+ statusReceiver.sendIntent(context, 1, intent, null, null);
+ } catch (SendIntentException e) {
+ Slog.w(TAG, e);
+ }
+ });
+ }
+
+ private static @NonNull Certificate[] decodeCertificates(@NonNull List certs) {
+ try {
+ final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ final Certificate[] result = new Certificate[certs.size()];
+ for (int i = 0, size = certs.size(); i < size; ++i) {
+ final InputStream is = new ByteArrayInputStream((byte[]) certs.get(i));
+ final X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
+ result[i] = cert;
+ }
+ return result;
+ } catch (CertificateException e) {
+ throw ExceptionUtils.propagate(e);
+ }
+ }
+
/**
* Gets the type of the external storage a package is installed on.
* @param packageVolume The storage volume of the package.
@@ -8964,10 +9051,10 @@
if (providerInfo == null) {
return null;
}
- if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
- return null;
- }
synchronized (mLock) {
+ if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
+ return null;
+ }
final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
final ComponentName component =
new ComponentName(providerInfo.packageName, providerInfo.name);
@@ -9054,9 +9141,11 @@
String targetPackage, int flags) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- final PackageSetting ps = mSettings.mPackages.get(targetPackage);
- if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
- return ParceledListSlice.emptyList();
+ synchronized (mLock) {
+ final PackageSetting ps = mSettings.getPackageLPr(targetPackage);
+ if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
+ return ParceledListSlice.emptyList();
+ }
}
return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags,
callingUserId));
@@ -11587,7 +11676,7 @@
configurePackageComponents(parsedPackage);
}
- final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride, pkgSetting);
+ final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride);
final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp();
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
@@ -13793,7 +13882,7 @@
final boolean isCallerOwner = isCallerDeviceOrProfileOwner(userId);
final long callingId = Binder.clearCallingIdentity();
try {
- final String activeLauncherPackageName = getActiveLauncherPackageName(userId);
+ final String activeLauncherPackageName = mPermissionManager.getDefaultHome(userId);
final String dialerPackageName = mPermissionManager.getDefaultDialer(userId);
for (int i = 0; i < packageNames.length; i++) {
canSuspend[i] = false;
@@ -13869,18 +13958,6 @@
return canSuspend;
}
- private String getActiveLauncherPackageName(int userId) {
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = resolveIntent(
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- PackageManager.MATCH_DEFAULT_ONLY,
- userId);
-
- return resolveInfo == null ? null : resolveInfo.activityInfo.packageName;
- }
-
@Override
public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
mContext.enforceCallingOrSelfPermission(
@@ -14572,7 +14649,7 @@
final PackageSetting ps;
int appId = -1;
long ceDataInode = -1;
- synchronized (mSettings) {
+ synchronized (mLock) {
ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
appId = ps.appId;
@@ -17620,7 +17697,7 @@
}
boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null
&& pkgSetting.getPkgState().isUpdatedSystemApp();
- final String abiOverride = deriveAbiOverride(args.abiOverride, pkgSetting);
+ final String abiOverride = deriveAbiOverride(args.abiOverride);
AndroidPackage oldPackage = mPackages.get(pkgName);
boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem();
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
@@ -19453,6 +19530,9 @@
}
if (outInfo != null) {
+ if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+ outInfo.dataRemoved = true;
+ }
outInfo.removedPackage = ps.name;
outInfo.installerPackageName = ps.installSource.installerPackageName;
outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null;
@@ -19488,9 +19568,11 @@
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */, "clear application data");
- final PackageSetting ps = mSettings.getPackageLPr(packageName);
- final boolean filterApp =
- (ps != null && shouldFilterApplicationLocked(ps, callingUid, userId));
+ final boolean filterApp;
+ synchronized (mLock) {
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
+ filterApp = shouldFilterApplicationLocked(ps, callingUid, userId);
+ }
if (!filterApp && mProtectedPackages.isPackageDataProtected(userId, packageName)) {
throw new SecurityException("Cannot clear data for a protected package: "
+ packageName);
@@ -19770,11 +19852,13 @@
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (getUidTargetSdkVersionLockedLPr(callingUid)
- < Build.VERSION_CODES.FROYO) {
- Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
- + callingUid);
- return;
+ synchronized (mLock) {
+ if (getUidTargetSdkVersionLockedLPr(callingUid)
+ < Build.VERSION_CODES.FROYO) {
+ Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
+ + callingUid);
+ return;
+ }
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
@@ -19954,8 +20038,9 @@
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
private void clearPackagePreferredActivities(String packageName, int userId) {
final SparseBooleanArray changedUsers = new SparseBooleanArray();
-
- clearPackagePreferredActivitiesLPw(packageName, changedUsers, userId);
+ synchronized (mLock) {
+ clearPackagePreferredActivitiesLPw(packageName, changedUsers, userId);
+ }
if (changedUsers.size() > 0) {
updateDefaultHomeNotLocked(changedUsers);
postPreferredActivityChangedBroadcast(userId);
@@ -20077,7 +20162,9 @@
// writer
try {
final SparseBooleanArray changedUsers = new SparseBooleanArray();
- clearPackagePreferredActivitiesLPw(null, changedUsers, userId);
+ synchronized (mLock) {
+ clearPackagePreferredActivitiesLPw(null, changedUsers, userId);
+ }
if (changedUsers.size() > 0) {
postPreferredActivityChangedBroadcast(userId);
}
@@ -20545,6 +20632,9 @@
if (cn != null) {
return cn;
}
+ // TODO: This should not happen since there should always be a default package set for
+ // ROLE_HOME in RoleManager. Continue with a warning log for now.
+ Slog.w(TAG, "Default package for ROLE_HOME is not set in RoleManager");
// Find the launcher with the highest priority and return that component if there are no
// other home activity with the same priority.
@@ -20593,6 +20683,7 @@
if (packageName == null) {
return null;
}
+
int resolveInfosSize = resolveInfos.size();
for (int i = 0; i < resolveInfosSize; i++) {
ResolveInfo resolveInfo = resolveInfos.get(i);
@@ -20652,6 +20743,11 @@
// PermissionController manages default home directly.
return false;
}
+
+ if (packageName == null) {
+ // Keep the default home package in RoleManager.
+ return false;
+ }
mPermissionManager.setDefaultHome(packageName, userId, (successful) -> {
if (successful) {
postPreferredActivityChangedBroadcast(userId);
@@ -21087,15 +21183,19 @@
// Limit who can change which apps
if (!UserHandle.isSameApp(callingUid, pkgSetting.appId)) {
// Don't allow apps that don't have permission to modify other apps
- if (!allowedByPermission
- || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
+ final boolean filterApp;
+ synchronized (mLock) {
+ filterApp = (!allowedByPermission
+ || shouldFilterApplicationLocked(pkgSetting, callingUid, userId));
+ }
+ if (filterApp) {
throw new SecurityException(
"Attempt to change component state; "
- + "pid=" + Binder.getCallingPid()
- + ", uid=" + callingUid
- + (className == null
+ + "pid=" + Binder.getCallingPid()
+ + ", uid=" + callingUid
+ + (className == null
? ", package=" + packageName
- : ", component=" + packageName + "/" + className));
+ : ", component=" + packageName + "/" + className));
}
// Don't allow changing protected packages.
if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 491b4fc..5553cd0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -421,18 +421,13 @@
/**
* Derive the value of the {@code cpuAbiOverride} based on the provided
- * value and an optional stored value from the package settings.
+ * value.
*/
- public static String deriveAbiOverride(String abiOverride, PackageSetting settings) {
- String cpuAbiOverride = null;
+ public static String deriveAbiOverride(String abiOverride) {
if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
- cpuAbiOverride = null;
- } else if (abiOverride != null) {
- cpuAbiOverride = abiOverride;
- } else if (settings != null) {
- cpuAbiOverride = settings.cpuAbiOverrideString;
+ return null;
}
- return cpuAbiOverride;
+ return abiOverride;
}
/**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 137c587..d01a30f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -69,6 +69,7 @@
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -148,6 +149,7 @@
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
+import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
@@ -1378,12 +1380,14 @@
}
private long getScreenshotChordLongPressDelay() {
+ long delayMs = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_SYSTEMUI, SCREENSHOT_KEYCHORD_DELAY,
+ ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout());
if (mKeyguardDelegate.isShowing()) {
// Double the time it takes to take a screenshot from the keyguard
- return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
- ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout());
+ return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER * delayMs);
}
- return ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout();
+ return delayMs;
}
private long getRingerToggleChordDelay() {
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 2b793c8..f204aa2 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -52,6 +52,9 @@
/** The maximum size of signature file. This is just to avoid potential abuse. */
private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192;
+ /** SHA256 hash size. */
+ private static final int HASH_SIZE_BYTES = 32;
+
private static final boolean DEBUG = false;
/** Returns true if the given file looks like containing an fs-verity signature. */
@@ -90,8 +93,23 @@
return (retval == 1);
}
+ /** Returns hash of a root node for the fs-verity enabled file. */
+ public static byte[] getFsverityRootHash(@NonNull String filePath) {
+ byte[] result = new byte[HASH_SIZE_BYTES];
+ int retval = measureFsverityNative(filePath, result);
+ if (retval < 0) {
+ if (retval != -OsConstants.ENODATA) {
+ Slog.e(TAG, "Failed to measure fs-verity, errno " + -retval + ": " + filePath);
+ }
+ return null;
+ }
+ return result;
+ }
+
private static native int enableFsverityNative(@NonNull String filePath,
@NonNull byte[] pkcs7Signature);
+ private static native int measureFsverityNative(@NonNull String filePath,
+ @NonNull byte[] digest);
private static native int statxForFsverityNative(@NonNull String filePath);
/**
diff --git a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
new file mode 100644
index 0000000..91e172c
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.timezonedetector."
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index 9a397fe..01c007e 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -18,6 +18,9 @@
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
+
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -25,6 +28,8 @@
import android.window.IDisplayAreaOrganizer;
import android.window.IDisplayAreaOrganizerController;
+import com.android.internal.protolog.common.ProtoLog;
+
import java.util.HashMap;
public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerController.Stub {
@@ -67,9 +72,12 @@
@Override
public void registerOrganizer(IDisplayAreaOrganizer organizer, int feature) {
enforceStackPermission("registerOrganizer()");
+ final long uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register display organizer=%s uid=%d",
+ organizer.asBinder(), uid);
if (mOrganizersByFeatureIds.get(feature) != null) {
throw new IllegalStateException(
"Replacing existing organizer currently unsupported");
@@ -96,9 +104,12 @@
@Override
public void unregisterOrganizer(IDisplayAreaOrganizer organizer) {
enforceStackPermission("unregisterTaskOrganizer()");
+ final long uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister display organizer=%s uid=%d",
+ organizer.asBinder(), uid);
mOrganizersByFeatureIds.entrySet().removeIf(
entry -> entry.getValue().asBinder() == organizer.asBinder());
@@ -113,6 +124,7 @@
}
void onDisplayAreaAppeared(IDisplayAreaOrganizer organizer, DisplayArea da) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea appeared name=%s", da.getName());
try {
SurfaceControl outSurfaceControl = new SurfaceControl(da.getSurfaceControl(),
"DisplayAreaOrganizerController.onDisplayAreaAppeared");
@@ -123,6 +135,7 @@
}
void onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea vanished name=%s", da.getName());
try {
organizer.onDisplayAreaVanished(da.getDisplayAreaInfo());
} catch (RemoteException e) {
@@ -131,6 +144,7 @@
}
void onDisplayAreaInfoChanged(IDisplayAreaOrganizer organizer, DisplayArea da) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea info changed name=%s", da.getName());
try {
organizer.onDisplayAreaInfoChanged(da.getDisplayAreaInfo());
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 33935d6..7df2b40 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -26,6 +26,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.util.DebugUtils;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
@@ -429,7 +430,8 @@
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mLeash="); pw.print(mLeash);
- pw.print(" mAnimationType=" + mAnimationType);
+ pw.print(" mAnimationType=" + DebugUtils.valueToString(SurfaceAnimator.class,
+ "ANIMATION_TYPE_", mAnimationType));
pw.println(mAnimationStartDelayed ? " mAnimationStartDelayed=true" : "");
pw.print(prefix); pw.print("Animation: "); pw.println(mAnimation);
if (mAnimation != null) {
@@ -442,56 +444,56 @@
* No animation is specified.
* @hide
*/
- static final int ANIMATION_TYPE_NONE = 0;
+ public static final int ANIMATION_TYPE_NONE = 0;
/**
* Animation for an app transition.
* @hide
*/
- static final int ANIMATION_TYPE_APP_TRANSITION = 1;
+ public static final int ANIMATION_TYPE_APP_TRANSITION = 1;
/**
* Animation for screen rotation.
* @hide
*/
- static final int ANIMATION_TYPE_SCREEN_ROTATION = 1 << 1;
+ public static final int ANIMATION_TYPE_SCREEN_ROTATION = 1 << 1;
/**
* Animation for dimming.
* @hide
*/
- static final int ANIMATION_TYPE_DIMMER = 1 << 2;
+ public static final int ANIMATION_TYPE_DIMMER = 1 << 2;
/**
* Animation for recent apps.
* @hide
*/
- static final int ANIMATION_TYPE_RECENTS = 1 << 3;
+ public static final int ANIMATION_TYPE_RECENTS = 1 << 3;
/**
* Animation for a {@link WindowState} without animating the activity.
* @hide
*/
- static final int ANIMATION_TYPE_WINDOW_ANIMATION = 1 << 4;
+ public static final int ANIMATION_TYPE_WINDOW_ANIMATION = 1 << 4;
/**
* Animation to control insets. This is actually not an animation, but is used to give the
* client a leash over the system window causing insets.
* @hide
*/
- static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5;
+ public static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5;
/**
* Animation when a fixed rotation transform is applied to a window token.
* @hide
*/
- static final int ANIMATION_TYPE_FIXED_TRANSFORM = 1 << 6;
+ public static final int ANIMATION_TYPE_FIXED_TRANSFORM = 1 << 6;
/**
* Bitmask to include all animation types. This is NOT an {@link AnimationType}
* @hide
*/
- static final int ANIMATION_TYPE_ALL = -1;
+ public static final int ANIMATION_TYPE_ALL = -1;
/**
* The type of the animation.
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index f8465dd..63a595e 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -23,6 +23,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
@@ -37,19 +38,20 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
import android.window.WindowContainerToken;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
-import java.util.LinkedHashMap;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -126,6 +128,7 @@
}
void onTaskAppeared(Task task) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId);
final boolean visible = task.isVisible();
final RunningTaskInfo taskInfo = task.getTaskInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
@@ -147,6 +150,7 @@
void onTaskVanished(Task task) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task vanished taskId=%d", task.mTaskId);
final RunningTaskInfo taskInfo = task.getTaskInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
try {
@@ -163,6 +167,7 @@
// by the organizer that don't receive that signal
return;
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId);
mDeferTaskOrgCallbacksConsumer.accept(() -> {
if (!task.isOrganized()) {
// This is safe to ignore if the task is no longer organized
@@ -177,6 +182,8 @@
}
void onBackPressedOnTaskRoot(Task task) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task back pressed on root taskId=%d",
+ task.mTaskId);
if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) {
// Skip if the task has not yet received taskAppeared(), except for tasks created
// by the organizer that don't receive that signal
@@ -201,7 +208,6 @@
private final DeathRecipient mDeathRecipient;
private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
private final int mUid;
- private boolean mInterceptBackPressedOnTaskRoot;
TaskOrganizerState(ITaskOrganizer organizer, int uid) {
final Consumer<Runnable> deferTaskOrgCallbacksConsumer =
@@ -219,10 +225,6 @@
mUid = uid;
}
- void setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed) {
- mInterceptBackPressedOnTaskRoot = interceptBackPressed;
- }
-
void addTask(Task t) {
if (t.mTaskAppearedSent) return;
@@ -242,6 +244,7 @@
mOrganizer.onTaskVanished(t);
}
mOrganizedTasks.remove(t);
+ mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
}
void dispose() {
@@ -273,6 +276,8 @@
private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
+ // Set of organized tasks (by taskId) that dispatch back pressed to their organizers
+ private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet();
private final ActivityTaskManagerService mService;
@@ -306,6 +311,8 @@
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task organizer=%s uid=%d",
+ organizer.asBinder(), uid);
for (int winMode : SUPPORTED_WINDOWING_MODES) {
if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
mTaskOrganizers.add(organizer);
@@ -327,6 +334,7 @@
@Override
public void unregisterTaskOrganizer(ITaskOrganizer organizer) {
enforceStackPermission("unregisterTaskOrganizer()");
+ final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -334,6 +342,8 @@
if (state == null) {
return;
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister task organizer=%s uid=%d",
+ organizer.asBinder(), uid);
state.unlinkDeath();
state.dispose();
}
@@ -383,6 +393,8 @@
return null;
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create root task displayId=%d winMode=%d",
+ displayId, windowingMode);
final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode,
ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(),
true /* createdByOrganizer */);
@@ -407,6 +419,9 @@
throw new IllegalArgumentException(
"Attempt to delete task not created by organizer task=" + task);
}
+
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete root task display=%d winMode=%d",
+ task.getDisplayId(), task.getWindowingMode());
task.removeImmediately();
return true;
}
@@ -608,15 +623,23 @@
}
@Override
- public void setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer,
+ public void setInterceptBackPressedOnTaskRoot(WindowContainerToken token,
boolean interceptBackPressed) {
enforceStackPermission("setInterceptBackPressedOnTaskRoot()");
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
- if (state != null) {
- state.setInterceptBackPressedOnTaskRoot(interceptBackPressed);
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set intercept back pressed on root=%b",
+ interceptBackPressed);
+ final Task task = WindowContainer.fromBinder(token.asBinder()).asTask();
+ if (task == null) {
+ Slog.w(TAG, "Could not resolve task from token");
+ return;
+ }
+ if (interceptBackPressed) {
+ mInterceptBackPressedOnRootTasks.add(task.mTaskId);
+ } else {
+ mInterceptBackPressedOnRootTasks.remove(task.mTaskId);
}
}
} finally {
@@ -625,15 +648,12 @@
}
public boolean handleInterceptBackPressedOnTaskRoot(Task task) {
- if (task == null || !task.isOrganized()) {
+ if (task == null || !task.isOrganized()
+ || !mInterceptBackPressedOnRootTasks.contains(task.mTaskId)) {
return false;
}
final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder());
- if (!state.mInterceptBackPressedOnTaskRoot) {
- return false;
- }
-
state.mOrganizer.onBackPressedOnTaskRoot(task);
return true;
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index d25a648..c7cad2f 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
@@ -45,6 +46,7 @@
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -127,6 +129,8 @@
if (callback != null) {
syncId = startSyncWithOrganizer(callback);
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d",
+ syncId);
mService.deferWindowLayout();
try {
ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
@@ -427,6 +431,7 @@
@VisibleForTesting
void setSyncReady(int id) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set sync ready, syncId=%d", id);
mBLASTSyncEngine.setReady(id);
}
@@ -436,9 +441,10 @@
}
@Override
- public void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady) {
+ public void onTransactionReady(int syncId, Set<WindowContainer> windowContainersReady) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Transaction ready, syncId=%d", syncId);
final IWindowContainerTransactionCallback callback =
- mTransactionCallbacksByPendingSyncId.get(mSyncId);
+ mTransactionCallbacksByPendingSyncId.get(syncId);
SurfaceControl.Transaction mergedTransaction = new SurfaceControl.Transaction();
for (WindowContainer container : windowContainersReady) {
@@ -446,14 +452,14 @@
}
try {
- callback.onTransactionReady(mSyncId, mergedTransaction);
+ callback.onTransactionReady(syncId, mergedTransaction);
} catch (RemoteException e) {
// If there's an exception when trying to send the mergedTransaction to the client, we
// should immediately apply it here so the transactions aren't lost.
mergedTransaction.apply();
}
- mTransactionCallbacksByPendingSyncId.remove(mSyncId);
+ mTransactionCallbacksByPendingSyncId.remove(syncId);
}
@Override
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index 0277f16..46e6f91 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -33,6 +33,8 @@
#include <android-base/unique_fd.h>
+#include <type_traits>
+
namespace android {
namespace {
@@ -53,7 +55,7 @@
fsverity_enable_arg arg = {};
arg.version = 1;
- arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
+ arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; // hardcoded in measureFsverity below
arg.block_size = 4096;
arg.salt_size = 0;
arg.salt_ptr = reinterpret_cast<uintptr_t>(nullptr);
@@ -85,9 +87,41 @@
return (out.stx_attributes & STATX_ATTR_VERITY) != 0;
}
+int measureFsverity(JNIEnv *env, jobject /* clazz */, jstring filePath, jbyteArray digest) {
+ static constexpr auto kDigestSha256 = 32;
+ using Storage = std::aligned_storage_t<sizeof(fsverity_digest) + kDigestSha256>;
+
+ Storage bytes;
+ fsverity_digest *data = reinterpret_cast<fsverity_digest *>(&bytes);
+ data->digest_size = kDigestSha256; // the only input/output parameter
+
+ ScopedUtfChars path(env, filePath);
+ ::android::base::unique_fd rfd(open(path.c_str(), O_RDONLY | O_CLOEXEC));
+ if (rfd.get() < 0) {
+ return rfd.get();
+ }
+ if (auto err = ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data); err < 0) {
+ return err;
+ }
+
+ if (data->digest_algorithm != FS_VERITY_HASH_ALG_SHA256) {
+ return -EINVAL;
+ }
+
+ if (digest != nullptr && data->digest_size > 0) {
+ auto digestSize = env->GetArrayLength(digest);
+ if (data->digest_size > digestSize) {
+ return -E2BIG;
+ }
+ env->SetByteArrayRegion(digest, 0, data->digest_size, (const jbyte *)data->digest);
+ }
+
+ return 0;
+}
const JNINativeMethod sMethods[] = {
{"enableFsverityNative", "(Ljava/lang/String;[B)I", (void *)enableFsverity},
{"statxForFsverityNative", "(Ljava/lang/String;)I", (void *)statxForFsverity},
+ {"measureFsverityNative", "(Ljava/lang/String;[B)I", (void *)measureFsverity},
};
} // namespace
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 22e309c..277218d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -12052,14 +12052,6 @@
}
@Override
- public boolean isSystemOnlyUser(ComponentName admin) {
- Objects.requireNonNull(admin, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
- return UserManager.isSplitSystemUser() && identity.getUserId() == UserHandle.USER_SYSTEM;
- }
-
- @Override
public void reboot(ComponentName admin) {
Objects.requireNonNull(admin, "ComponentName is null");
final CallerIdentity identity = getCallerIdentity(admin);
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index ba6ae92..9836262e 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1706,8 +1706,8 @@
}
if (totalBlocks == 0) {
- LOG(ERROR) << "getLoadingProgress failed to get total num of blocks";
- return -EINVAL;
+ // No file in the storage or files are empty; regarded as fully loaded
+ return 1;
}
return (float)filledBlocks / (float)totalBlocks;
}
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 44cef49..d1000e56 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -1069,7 +1069,7 @@
ASSERT_EQ(res, 0);
}
-TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithNoFile) {
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithNoFile) {
mIncFs->countFilledBlocksSuccess();
mFs->hasNoFile();
@@ -1077,7 +1077,7 @@
int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
IncrementalService::CreateOptions::CreateNew,
{}, {}, {});
- ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+ ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId));
}
TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
@@ -1092,7 +1092,7 @@
ASSERT_EQ(-1, mIncrementalService->getLoadingProgress(storageId));
}
-TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithEmptyRanges) {
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithEmptyRanges) {
mIncFs->countFilledBlocksEmpty();
mFs->hasFiles();
@@ -1101,7 +1101,7 @@
IncrementalService::CreateOptions::CreateNew,
{}, {}, {});
EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
- ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+ ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId));
}
TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccess) {
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 fdcadf3..d6894cf 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -33,6 +33,7 @@
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
import static com.android.server.location.LocationUtils.createLocation;
+import static com.android.server.location.listeners.RemoteListenerRegistration.IN_PROCESS_EXECUTOR;
import static com.google.common.truth.Truth.assertThat;
@@ -85,7 +86,6 @@
import com.android.internal.location.ProviderRequest;
import com.android.server.FgThread;
import com.android.server.LocalServices;
-import com.android.server.location.listeners.ListenerRegistration;
import com.android.server.location.util.FakeUserInfoHelper;
import com.android.server.location.util.TestInjector;
@@ -484,7 +484,7 @@
PERMISSION_FINE, listener);
CountDownLatch blocker = new CountDownLatch(1);
- ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+ IN_PROCESS_EXECUTOR.execute(() -> {
try {
blocker.await();
} catch (InterruptedException e) {
@@ -622,7 +622,7 @@
PERMISSION_FINE, listener);
CountDownLatch blocker = new CountDownLatch(1);
- ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+ IN_PROCESS_EXECUTOR.execute(() -> {
try {
blocker.await();
} catch (InterruptedException e) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
index 1ef1255..69a9f44 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
@@ -16,6 +16,8 @@
package com.android.server.location.listeners;
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -27,8 +29,6 @@
import static org.mockito.Mockito.verify;
import static org.testng.Assert.assertThrows;
-import android.location.util.identity.CallerIdentity;
-import android.os.Process;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -324,10 +324,8 @@
boolean mActive = true;
protected TestListenerRegistration(Integer integer,
- Consumer<TestListenerRegistration> consumer,
- boolean outOfProcess) {
- super(integer, CallerIdentity.forTest(Process.myUid(),
- Process.myPid() + (outOfProcess ? 1 : 0), "test", "test"), consumer);
+ Consumer<TestListenerRegistration> consumer) {
+ super(DIRECT_EXECUTOR, integer, consumer);
}
}
@@ -345,7 +343,7 @@
}
public void addListener(Integer request, Consumer<TestListenerRegistration> consumer) {
- addRegistration(consumer, new TestListenerRegistration(request, consumer, true));
+ addRegistration(consumer, new TestListenerRegistration(request, consumer));
}
public void removeListener(Consumer<TestListenerRegistration> consumer) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index bec9f26..a10e0ba 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -81,7 +81,7 @@
@After
public void tearDown() {
- mWindowMagnificationManager.disableWindowMagnifier(DISPLAY_0, true);
+ mWindowMagnificationManager.disableWindowMagnification(DISPLAY_0, true);
}
@Test
@@ -225,7 +225,7 @@
}
break;
case STATE_SHOW_MAGNIFIER: {
- mWindowMagnificationManager.disableWindowMagnifier(DISPLAY_0, false);
+ mWindowMagnificationManager.disableWindowMagnification(DISPLAY_0, false);
}
break;
case STATE_TWO_FINGERS_DOWN: {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index 70e6a34..e067b7e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -68,8 +68,10 @@
private static final int CURRENT_USER_ID = UserHandle.USER_CURRENT;
private MockWindowMagnificationConnection mMockConnection;
- @Mock private Context mContext;
- @Mock private StatusBarManagerInternal mMockStatusBarManagerInternal;
+ @Mock
+ private Context mContext;
+ @Mock
+ private StatusBarManagerInternal mMockStatusBarManagerInternal;
private MockContentResolver mResolver;
private WindowMagnificationManager mWindowMagnificationManager;
@@ -84,7 +86,7 @@
when(mContext.getContentResolver()).thenReturn(mResolver);
doAnswer((InvocationOnMock invocation) -> {
- final boolean connect = (Boolean) invocation.getArguments()[0];
+ final boolean connect = (Boolean) invocation.getArguments()[0];
mWindowMagnificationManager.setConnection(
connect ? mMockConnection.getConnection() : null);
return null;
@@ -161,7 +163,7 @@
public void enable_TestDisplay_enableWindowMagnification() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2f, 200f, 300f);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, 200f, 300f);
verify(mMockConnection.getConnection()).enableWindowMagnification(TEST_DISPLAY, 2f,
200f, 300f);
@@ -170,9 +172,9 @@
@Test
public void disable_testDisplay_disableWindowMagnification() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
- mWindowMagnificationManager.disableWindowMagnifier(TEST_DISPLAY, false);
+ mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false);
verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY);
}
@@ -183,7 +185,7 @@
assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, NaN, NaN);
assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
}
@@ -198,7 +200,7 @@
@Test
public void persistScale_setValue_expectedValueInProvider() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2.0f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.0f, NaN, NaN);
mWindowMagnificationManager.setScale(TEST_DISPLAY, 2.5f);
mWindowMagnificationManager.persistScale(TEST_DISPLAY);
@@ -211,7 +213,7 @@
@Test
public void scaleSetterGetter_enabledOnTestDisplay_expectedValue() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2.0f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.0f, NaN, NaN);
mWindowMagnificationManager.setScale(TEST_DISPLAY, 2.5f);
@@ -221,7 +223,7 @@
@Test
public void scaleSetterGetter_scaleIsOutOfRang_getNormalizeValue() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2.5f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.5f, NaN, NaN);
mWindowMagnificationManager.setScale(TEST_DISPLAY, 10.0f);
@@ -232,9 +234,9 @@
@Test
public void moveWindowMagnifier() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, NaN, NaN);
- mWindowMagnificationManager.moveWindowMagnifier(TEST_DISPLAY, 200, 300);
+ mWindowMagnificationManager.moveWindowMagnification(TEST_DISPLAY, 200, 300);
verify(mMockConnection.getConnection()).moveWindowMagnifier(TEST_DISPLAY, 200, 300);
}
@@ -254,7 +256,7 @@
@Test
public void pointersInWindow_returnCorrectValue() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3.0f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, NaN, NaN);
mMockConnection.getConnectionCallback().onWindowMagnifierBoundsChanged(TEST_DISPLAY,
new Rect(0, 0, 500, 500));
PointF[] pointersLocation = new PointF[2];
@@ -268,7 +270,7 @@
@Test
public void binderDied_windowMagnifierIsEnabled_resetState() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
mMockConnection.getDeathRecipient().binderDied();
@@ -280,7 +282,7 @@
requestConnectionToNull_disableAllMagnifiersAndRequestWindowMagnificationConnection()
throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
assertTrue(mWindowMagnificationManager.requestConnection(false));
@@ -306,21 +308,24 @@
@Test
public void requestConnection_registerAndUnregisterBroadcastReceiver() {
assertTrue(mWindowMagnificationManager.requestConnection(true));
- verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
+ verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
assertTrue(mWindowMagnificationManager.requestConnection(false));
verify(mContext).unregisterReceiver(any(BroadcastReceiver.class));
}
@Test
- public void onReceiveScreenOff_removeMagnificationButtonAndDisableWindowMagnification()
+ public void onScreenOff_windowMagnifierIsEnabled_removeButtonAndDisableWindowMagnification()
throws RemoteException {
mWindowMagnificationManager.requestConnection(true);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.5f, NaN, NaN);
+
mWindowMagnificationManager.mScreenStateReceiver.onReceive(mContext,
new Intent(Intent.ACTION_SCREEN_OFF));
verify(mMockConnection.getConnection()).removeMagnificationButton(TEST_DISPLAY);
verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY);
+ assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
}
private MotionEvent generatePointersDownEvent(PointF[] pointersLocation) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index ef2365e..3f324a2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.hdmi;
+import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -693,6 +694,82 @@
}
@Test
+ public void sendVolumeKeyEvent_toTv_activeSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(false);
+ mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_TV);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
+ public void sendVolumeKeyEvent_toAudio_activeSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(true);
+ mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
+ public void sendVolumeKeyEvent_toTv_inactiveSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(false);
+ mHdmiControlService.setActiveSource(ADDR_TV, 0x0000);
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_TV);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
+ public void sendVolumeKeyEvent_toAudio_inactiveSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(true);
+ mHdmiControlService.setActiveSource(ADDR_TV, 0x0000);
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
public void handleSetStreamPath_broadcastsActiveSource() {
HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
mPlaybackPhysicalAddress);
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 289d54e..46a6a82 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -930,23 +930,36 @@
final Task stack = createStack();
final Task task = createTask(stack);
final ActivityRecord activity = createActivityRecordInTask(stack.mDisplayContent, task);
+ final Task stack2 = createStack();
+ final Task task2 = createTask(stack2);
+ final ActivityRecord activity2 = createActivityRecordInTask(stack.mDisplayContent, task2);
final ITaskOrganizer organizer = registerMockOrganizer();
// Setup the task to be controlled by the MW mode organizer
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ stack2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
assertTrue(stack.isOrganized());
+ assertTrue(stack2.isOrganized());
// Verify a back pressed does not call the organizer
mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
verify(organizer, never()).onBackPressedOnTaskRoot(any());
// Enable intercepting back
- mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(organizer,
- true);
+ mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(
+ stack.mRemoteToken.toWindowContainerToken(), true);
// Verify now that the back press does call the organizer
mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
+
+ // Disable intercepting back
+ mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(
+ stack.mRemoteToken.toWindowContainerToken(), false);
+
+ // Verify now that the back press no longer calls the organizer
+ mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
+ verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
}
@Test
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 81aad97..f151d9c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -183,6 +183,7 @@
private static class ActivityData {
private final String mTaskRootPackage;
private final String mTaskRootClass;
+ public int lastEvent = Event.NONE;
private ActivityData(String taskRootPackage, String taskRootClass) {
mTaskRootPackage = taskRootPackage;
mTaskRootClass = taskRootClass;
@@ -785,6 +786,7 @@
switch (event.mEventType) {
case Event.ACTIVITY_RESUMED:
case Event.ACTIVITY_PAUSED:
+ case Event.ACTIVITY_STOPPED:
uid = mPackageManagerInternal.getPackageUid(event.mPackage, 0, userId);
break;
default:
@@ -817,8 +819,10 @@
.APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_FOREGROUND);
// check if this activity has already been resumed
if (mVisibleActivities.get(event.mInstanceId) != null) break;
- mVisibleActivities.put(event.mInstanceId,
- new ActivityData(event.mTaskRootPackage, event.mTaskRootClass));
+ final ActivityData resumedData = new ActivityData(event.mTaskRootPackage,
+ event.mTaskRootClass);
+ resumedData.lastEvent = Event.ACTIVITY_RESUMED;
+ mVisibleActivities.put(event.mInstanceId, resumedData);
try {
switch(mUsageSource) {
case USAGE_SOURCE_CURRENT_ACTIVITY:
@@ -834,16 +838,17 @@
}
break;
case Event.ACTIVITY_PAUSED:
- if (event.mTaskRootPackage == null) {
- // Task Root info is missing. Repair the event based on previous data
- final ActivityData prevData = mVisibleActivities.get(event.mInstanceId);
- if (prevData == null) {
- Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage
- + "/" + event.mClass + " event : " + event.mEventType
- + " instanceId : " + event.mInstanceId + ")");
- } else {
- event.mTaskRootPackage = prevData.mTaskRootPackage;
- event.mTaskRootClass = prevData.mTaskRootClass;
+ final ActivityData pausedData = mVisibleActivities.get(event.mInstanceId);
+ if (pausedData == null) {
+ Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage
+ + "/" + event.mClass + " event : " + event.mEventType
+ + " instanceId : " + event.mInstanceId + ")");
+ } else {
+ pausedData.lastEvent = Event.ACTIVITY_PAUSED;
+ if (event.mTaskRootPackage == null) {
+ // Task Root info is missing. Repair the event based on previous data
+ event.mTaskRootPackage = pausedData.mTaskRootPackage;
+ event.mTaskRootClass = pausedData.mTaskRootClass;
}
}
FrameworkStatsLog.write(
@@ -866,6 +871,16 @@
return;
}
+ if (prevData.lastEvent != Event.ACTIVITY_PAUSED) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.APP_USAGE_EVENT_OCCURRED,
+ uid,
+ event.mPackage,
+ event.mClass,
+ FrameworkStatsLog
+ .APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_BACKGROUND);
+ }
+
ArraySet<String> tokens;
synchronized (mUsageReporters) {
tokens = mUsageReporters.removeReturnOld(event.mInstanceId);
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 f50d2e1..702f871 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -84,7 +84,8 @@
Log.e(TAG, e);
}
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
- "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex");
+ "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
+ "/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex");
}
@Before
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a3673df..bcb5c99 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1199,7 +1199,7 @@
MockitoAnnotations.initMocks(this);
when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics);
- when(mUserManager.getUsers(eq(true))).thenReturn(
+ when(mUserManager.getAliveUsers()).thenReturn(
Arrays.asList(new UserInfo[] {
new UserInfo(VPN_USER, "", 0),
}));
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 5a29c2c..de35f91 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -123,7 +123,7 @@
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
- when(mUserManager.getUsers(eq(true))).thenReturn(
+ when(mUserManager.getAliveUsers()).thenReturn(
Arrays.asList(new UserInfo[] {
new UserInfo(MOCK_USER1, "", 0),
new UserInfo(MOCK_USER2, "", 0),
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index e8c4ee9..c76b4cd 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -1238,15 +1238,14 @@
* @see UserManagerService#getUsers(boolean)
*/
doAnswer(invocation -> {
- final boolean excludeDying = (boolean) invocation.getArguments()[0];
final ArrayList<UserInfo> result = new ArrayList<>(users.length);
for (UserInfo ui : users) {
- if (!excludeDying || (ui.isEnabled() && !ui.partial)) {
+ if (ui.isEnabled() && !ui.partial) {
result.add(ui);
}
}
return result;
- }).when(mUserManager).getUsers(anyBoolean());
+ }).when(mUserManager).getAliveUsers();
doAnswer(invocation -> {
final int id = (int) invocation.getArguments()[0];