diff options
228 files changed, 5042 insertions, 1987 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 41e859363581..00a59bf4f1e3 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -219,6 +219,7 @@ package android { 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 529dcf71ef6e..5741fe7e90a4 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5579,7 +5579,7 @@ package android.window { 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 3b65f8225ee9..4574b2e34547 100644 --- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp +++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp @@ -25,8 +25,9 @@ namespace statsd { 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 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf 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 a7fac3deaabe..672d61c82268 100644 --- a/cmds/statsd/src/condition/CombinationConditionTracker.h +++ b/cmds/statsd/src/condition/CombinationConditionTracker.h @@ -24,9 +24,9 @@ namespace android { 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 @@ public: 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 @@ private: 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 4e1253506be7..3bf4e636be89 100644 --- a/cmds/statsd/src/condition/ConditionTracker.h +++ b/cmds/statsd/src/condition/ConditionTracker.h @@ -31,18 +31,17 @@ namespace statsd { 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 @@ public: // 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 @@ public: 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 @@ public: 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 @@ protected: 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 @@ protected: 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 f45759b6a77e..1dcc8f96131a 100644 --- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp +++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp @@ -27,54 +27,21 @@ namespace statsd { 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 @@ bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig, 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 1a9e35e38207..7a8b40108448 100644 --- a/cmds/statsd/src/condition/SimpleConditionTracker.h +++ b/cmds/statsd/src/condition/SimpleConditionTracker.h @@ -27,11 +27,11 @@ namespace android { 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 @@ public: 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 @@ private: 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 @@ private: 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 5a520326116a..a0c701ea4229 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -80,7 +80,7 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, 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 @@ bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t time 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 6f4b2d7e9fa4..bd0c8161a884 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -242,9 +242,12 @@ private: // 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/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp index 0983dc0b2c83..bd60b6bfcb8e 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 @@ bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherI // 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 @@ bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherI 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 @@ bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, 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 @@ bool updateAtomTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, 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 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const 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 ae7b2162e034..7ba684a65e88 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 @@ namespace statsd { // 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 @@ bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherI // 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 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const 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 e40fbdb250f1..2e3e43413d54 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 @@ sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher, 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 @@ bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidM 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 @@ bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidM ALOGE("Duplicate AtomMatcher found!"); return false; } - atomMatchingTrackerMap[logMatcher.id()] = index; + atomMatchingTrackerMap[logMatcher.id()] = i; matcherConfigs.push_back(logMatcher); } @@ -307,28 +327,17 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config, 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 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp 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 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp 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 4cfd1b0465ea..6eabcf4971d3 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 @@ namespace statsd { 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 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config, 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 @@ bool initMetrics( 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 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp 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 07b5311b1207..8998b5f98df5 100644 --- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp +++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp @@ -39,6 +39,7 @@ const ConfigKey kConfigKey(0, 12345); 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 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueFalse) { 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 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueUnknown) { 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 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) { 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 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) { 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 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) { 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 @@ TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) { 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 @@ TEST(SimpleConditionTrackerTest, TestStopAll) { 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/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp index 8c698eb15d8d..890884bc5d83 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 @@ set<int> allTagIds; 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 @@ public: oldAtomMatchingTrackers.clear(); oldAtomMatchingTrackerMap.clear(); oldConditionTrackers.clear(); + oldConditionTrackerMap.clear(); oldMetricProducers.clear(); oldAnomalyTrackers.clear(); oldAlarmTrackers.clear(); @@ -93,8 +98,8 @@ bool initConfig(const StatsdConfig& config) { 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 @@ TEST_F(ConfigUpdateTest, TestSimpleMatcherReplace) { 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 @@ TEST_F(ConfigUpdateTest, TestUpdateMatchers) { 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 @@ TEST_F(ConfigUpdateTest, TestUpdateMatchers) { 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 d6db4c12ae4d..e6583c9686ec 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 @@ TEST(MetricsManagerTest, TestInitialConditions) { 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 @@ TEST(MetricsManagerTest, TestInitialConditions) { 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 @@ TEST(MetricsManagerTest, TestGoodConfig) { 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 @@ TEST(MetricsManagerTest, TestGoodConfig) { 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 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) { 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 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) { 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 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) { 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 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) { 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 @@ TEST(MetricsManagerTest, TestMissingMatchers) { 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 @@ TEST(MetricsManagerTest, TestMissingMatchers) { 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 @@ TEST(MetricsManagerTest, TestMissingPredicate) { 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 @@ TEST(MetricsManagerTest, TestMissingPredicate) { 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 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) { 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 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) { 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 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) { 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 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) { 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, testAlertWithUnknownMetric) { 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 @@ TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerCombination) { 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/ActivityThread.java b/core/java/android/app/ActivityThread.java index 763ce6c6fd17..caca05a9e3b3 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -5418,12 +5418,13 @@ public final class ActivityThread extends ClientTransactionHandler { final int prevState = r.getLifecycleState(); - if (prevState < ON_START || prevState > ON_STOP) { - Log.w(TAG, "Activity state must be in [ON_START..ON_STOP] in order to be relaunched," + if (prevState < ON_RESUME || prevState > ON_STOP) { + Log.w(TAG, "Activity state must be in [ON_RESUME..ON_STOP] in order to be relaunched," + "current state is " + prevState); return; } + // Initialize a relaunch request. final MergedConfiguration mergedConfiguration = new MergedConfiguration( r.createdConfig != null ? r.createdConfig : mConfiguration, diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index cee607fd7428..fef8d1005e29 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1924,10 +1924,8 @@ class ContextImpl extends Context { @Override public Object getSystemService(String name) { if (vmIncorrectContextUseEnabled()) { - // We may override this API from outer context. - final boolean isUiContext = isUiContext() || isOuterUiContext(); // Check incorrect Context usage. - if (isUiComponent(name) && !isUiContext) { + if (isUiComponent(name) && !isSelfOrOuterUiContext()) { final String errorMessage = "Tried to access visual service " + SystemServiceRegistry.getSystemServiceClassName(name) + " from a non-visual Context:" + getOuterContext(); @@ -1944,15 +1942,17 @@ class ContextImpl extends Context { return SystemServiceRegistry.getSystemService(this, name); } - private boolean isOuterUiContext() { - return getOuterContext() != null && getOuterContext().isUiContext(); - } - @Override public String getSystemServiceName(Class<?> serviceClass) { return SystemServiceRegistry.getSystemServiceName(serviceClass); } + // TODO(b/149463653): check if we still need this method after migrating IMS to WindowContext. + private boolean isSelfOrOuterUiContext() { + // We may override outer context's isUiContext + return isUiContext() || getOuterContext() != null && getOuterContext().isUiContext(); + } + /** @hide */ @Override public boolean isUiContext() { @@ -2413,7 +2413,7 @@ class ContextImpl extends Context { context.setResources(createResources(mToken, mPackageInfo, mSplitName, overrideDisplayId, overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo(), mResources.getLoaders())); - context.mIsUiContext = isUiContext() || isOuterUiContext(); + context.mIsUiContext = isSelfOrOuterUiContext(); return context; } @@ -2529,9 +2529,9 @@ class ContextImpl extends Context { @Override public Display getDisplay() { - if (!mIsSystemOrSystemUiContext && !mIsAssociatedWithDisplay) { + if (!mIsSystemOrSystemUiContext && !mIsAssociatedWithDisplay && !isSelfOrOuterUiContext()) { throw new UnsupportedOperationException("Tried to obtain display from a Context not " - + "associated with one. Only visual Contexts (such as Activity or one created " + + "associated with one. Only visual Contexts (such as Activity or one created " + "with Context#createWindowContext) or ones created with " + "Context#createDisplayContext are associated with displays. Other types of " + "Contexts are typically related to background entities and may return an " diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index c61426d5c172..98de85d9735d 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -9751,21 +9751,6 @@ public class DevicePolicyManager { } /** - * @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 9c6a274ccf8c..1c7b617e6d9a 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -345,7 +345,6 @@ interface IDevicePolicyManager { 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/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java index 56bf59b52f74..a34be5c3edc7 100644 --- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java +++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java @@ -185,9 +185,6 @@ public class TransactionExecutorHelper { final ActivityLifecycleItem lifecycleItem; switch (prevState) { // TODO(lifecycler): Extend to support all possible states. - case ON_START: - lifecycleItem = StartActivityItem.obtain(); - break; case ON_PAUSE: lifecycleItem = PauseActivityItem.obtain(); break; diff --git a/core/java/android/companion/TEST_MAPPING b/core/java/android/companion/TEST_MAPPING new file mode 100644 index 000000000000..63f54fa35158 --- /dev/null +++ b/core/java/android/companion/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "CtsOsTestCases", + "options": [ + { + "include-filter": "android.os.cts.CompanionDeviceManagerTest" + } + ] + } + ] +} diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index da8d15af92b8..d672c6ac6c2f 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -788,7 +788,6 @@ public abstract class PackageManager { INSTALL_ENABLE_ROLLBACK, INSTALL_ALLOW_DOWNGRADE, INSTALL_STAGED, - INSTALL_DRY_RUN, }) @Retention(RetentionPolicy.SOURCE) public @interface InstallFlags {} @@ -966,14 +965,6 @@ public abstract class PackageManager { */ public static final int INSTALL_STAGED = 0x00200000; - /** - * Flag parameter for {@link #installPackage} to indicate that package should only be verified - * but not installed. - * - * @hide - */ - public static final int INSTALL_DRY_RUN = 0x00800000; - /** @hide */ @IntDef(flag = true, value = { DONT_KILL_APP, diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java index bd909c7a3f59..192470e964e0 100644 --- a/core/java/android/content/pm/RegisteredServicesCache.java +++ b/core/java/android/content/pm/RegisteredServicesCache.java @@ -43,11 +43,11 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; -import libcore.io.IoUtils; - import com.google.android.collect.Lists; import com.google.android.collect.Maps; +import libcore.io.IoUtils; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -793,7 +793,7 @@ public abstract class RegisteredServicesCache<V> { @VisibleForTesting protected List<UserInfo> getUsers() { - return UserManager.get(mContext).getUsers(true); + return UserManager.get(mContext).getAliveUsers(); } @VisibleForTesting diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 7250801eec81..55afefed734e 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1210,15 +1210,19 @@ public class InputMethodService extends AbstractInputMethodService { mWindow.getWindow().getAttributes().setFitInsetsIgnoringVisibility(true); // IME layout should always be inset by navigation bar, no matter its current visibility, - // unless automotive requests it, since automotive may hide the navigation bar. + // unless automotive requests it. Automotive devices may request the navigation bar to be + // hidden when the IME shows up (controlled via config_automotiveHideNavBarForKeyboard) + // in order to maximize the visible screen real estate. When this happens, the IME window + // should animate from the bottom of the screen to reduce the jank that happens from the + // lack of synchronization between the bottom system window and the IME window. + if (mIsAutomotive && mAutomotiveHideNavBarForKeyboard) { + mWindow.getWindow().setDecorFitsSystemWindows(false); + } mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener( (v, insets) -> v.onApplyWindowInsets( new WindowInsets.Builder(insets).setInsets( navigationBars(), - mIsAutomotive && mAutomotiveHideNavBarForKeyboard - ? android.graphics.Insets.NONE - : insets.getInsetsIgnoringVisibility(navigationBars()) - ) + insets.getInsetsIgnoringVisibility(navigationBars())) .build())); // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set diff --git a/core/java/android/inputmethodservice/TEST_MAPPING b/core/java/android/inputmethodservice/TEST_MAPPING new file mode 100644 index 000000000000..0ccd75dcbdce --- /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 2465b0e41876..81ffefd05b19 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -43,7 +43,6 @@ import android.content.IntentFilter; 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; @@ -1294,7 +1293,7 @@ public class UserManager { * in {@link UserManager} & {@link DevicePolicyManager}. * Note: This is slightly different from the real set of user restrictions listed in {@link * com.android.server.pm.UserRestrictionsUtils#USER_RESTRICTIONS}. For example - * {@link #KEY_RESTRICTIONS_PENDING} is not a real user restriction, but is a a legitimate + * {@link #KEY_RESTRICTIONS_PENDING} is not a real user restriction, but is a legitimate * value that can be passed into {@link #hasUserRestriction(String)}. * @hide */ @@ -3174,28 +3173,55 @@ public class UserManager { } /** - * 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. + * + * <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. * - * @return the list of users that exist on the device. * @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...). + * + * <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)}. * - * @param excludeDying specify if the list should exclude users being - * removed. * @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); @@ -3226,7 +3252,8 @@ public class UserManager { @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public @NonNull List<UserHandle> getUserHandles(boolean excludeDying) { - List<UserInfo> users = getUsers(excludeDying); + List<UserInfo> users = getUsers(/* excludePartial= */ true, excludeDying, + /* excludePreCreated= */ true); List<UserHandle> result = new ArrayList<>(users.size()); for (UserInfo user : users) { result.add(user.getUserHandle()); @@ -3244,7 +3271,8 @@ public class UserManager { @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean excludeDying) { - List<UserInfo> users = getUsers(excludeDying); + List<UserInfo> users = getUsers(/* excludePartial= */ true, excludeDying, + /* excludePreCreated= */ true); long[] result = new long[users.size()]; for (int i = 0; i < result.length; i++) { result[i] = users.get(i).serialNumber; @@ -3310,7 +3338,7 @@ public class UserManager { public boolean canAddMoreUsers() { // TODO(b/142482943): UMS has different logic, excluding Demo and Profile from counting. Why // not here? The logic is inconsistent. See UMS.canAddMoreManagedProfiles - final List<UserInfo> users = getUsers(true); + final List<UserInfo> users = getAliveUsers(); final int totalUserCount = users.size(); int aliveUserCount = 0; for (int i = 0; i < totalUserCount; i++) { @@ -4118,7 +4146,7 @@ public class UserManager { /** Returns whether there are any users (other than the current user) to which to switch. */ private boolean areThereUsersToWhichToSwitch() { - final List<UserInfo> users = getUsers(true); + final List<UserInfo> users = getAliveUsers(); if (users == null) { return false; } diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 276f16216b4d..c3b6d8e2cfe3 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -870,7 +870,7 @@ public class CallLog { // Otherwise, insert to all other users that are running and unlocked. - final List<UserInfo> users = userManager.getUsers(true); + final List<UserInfo> users = userManager.getAliveUsers(); final int count = users.size(); for (int i = 0; i < count; i++) { diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 327bca268a7b..d55fc511fc77 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -218,8 +218,15 @@ public abstract class DocumentsProvider extends ContentProvider { } /** {@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 @@ public abstract class DocumentsProvider extends ContentProvider { 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 @@ public abstract class DocumentsProvider extends ContentProvider { "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/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index b80718018652..cbc304b3293a 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -950,10 +950,6 @@ public class PhoneStateListener { * This method will be called when an emergency call is placed on any subscription (including * the no-SIM case), regardless of which subscription this listener was registered on. * - * This method is deprecated. Both this method and the new - * {@link #onOutgoingEmergencyCall(EmergencyNumber, int)} will be called when an outgoing - * emergency call is placed. - * * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was placed to. * * @deprecated Use {@link #onOutgoingEmergencyCall(EmergencyNumber, int)}. @@ -972,22 +968,24 @@ public class PhoneStateListener { * This method will be called when an emergency call is placed on any subscription (including * the no-SIM case), regardless of which subscription this listener was registered on. * - * Both this method and the deprecated {@link #onOutgoingEmergencyCall(EmergencyNumber)} will be - * called when an outgoing emergency call is placed. You should only implement one of these - * methods. + * The default implementation of this method calls + * {@link #onOutgoingEmergencyCall(EmergencyNumber)} for backwards compatibility purposes. Do + * not call {@code super(...)} from within your implementation unless you want + * {@link #onOutgoingEmergencyCall(EmergencyNumber)} to be called as well. * * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was placed to. * @param subscriptionId The subscription ID used to place the emergency call. If the * emergency call was placed without a valid subscription (e.g. when there * are no SIM cards in the device), this will be equal to * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}. - * * @hide */ @SystemApi @TestApi public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber, int subscriptionId) { + // Default implementation for backwards compatibility + onOutgoingEmergencyCall(placedEmergencyNumber); } /** @@ -1375,10 +1373,6 @@ public class PhoneStateListener { Binder.withCleanCallingIdentity( () -> mExecutor.execute( - () -> psl.onOutgoingEmergencyCall(placedEmergencyNumber))); - - Binder.withCleanCallingIdentity( - () -> mExecutor.execute( () -> psl.onOutgoingEmergencyCall(placedEmergencyNumber, subscriptionId))); } diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java index 054dff726ca1..32cc30be8de4 100644 --- a/core/java/android/view/FrameMetrics.java +++ b/core/java/android/view/FrameMetrics.java @@ -250,8 +250,11 @@ public final class FrameMetrics { Index.INTENDED_VSYNC, Index.FRAME_COMPLETED, }; + /** + * @hide + */ @UnsupportedAppUsage - /* package */ final long[] mTimingData; + public final long[] mTimingData; /** * Constructs a FrameMetrics object as a copy. @@ -270,7 +273,7 @@ public final class FrameMetrics { /** * @hide */ - FrameMetrics() { + public FrameMetrics() { mTimingData = new long[Index.FRAME_STATS_COUNT]; } diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java index 6136a80978b7..0c3d61f31dfb 100644 --- a/core/java/android/view/NotificationHeaderView.java +++ b/core/java/android/view/NotificationHeaderView.java @@ -456,8 +456,8 @@ public class NotificationHeaderView extends ViewGroup { 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 000000000000..4b2ea1a096c8 --- /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 92fa80e40caf..12b16ff6645c 100644 --- a/core/java/android/window/ITaskOrganizerController.aidl +++ b/core/java/android/window/ITaskOrganizerController.aidl @@ -60,5 +60,6 @@ interface ITaskOrganizerController { * 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 7ec4f99ce959..38fb023a0822 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -149,9 +149,10 @@ public class TaskOrganizer extends WindowOrganizer { * 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 46c72f88e14b..eb9dfed7f644 100644 --- a/core/java/android/window/TaskOrganizerTaskEmbedder.java +++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java @@ -74,7 +74,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { // 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/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java new file mode 100644 index 000000000000..f9a2ecc10dc8 --- /dev/null +++ b/core/java/com/android/internal/jank/FrameTracker.java @@ -0,0 +1,234 @@ +/* + * 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.jank; + +import android.annotation.NonNull; +import android.graphics.HardwareRendererObserver; +import android.os.Handler; +import android.os.Trace; +import android.util.Log; +import android.view.FrameMetrics; +import android.view.ThreadedRenderer; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.jank.InteractionJankMonitor.Session; + +/** + * @hide + */ +public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvailableListener { + private static final String TAG = FrameTracker.class.getSimpleName(); + private static final boolean DEBUG = false; + //TODO (163431584): need also consider other refresh rates. + private static final long CRITERIA = 1000000000 / 60; + @VisibleForTesting + public static final long UNKNOWN_TIMESTAMP = -1; + + @VisibleForTesting + public long mBeginTime = UNKNOWN_TIMESTAMP; + @VisibleForTesting + public long mEndTime = UNKNOWN_TIMESTAMP; + public boolean mShouldTriggerTrace; + public HardwareRendererObserver mObserver; + public ThreadedRendererWrapper mRendererWrapper; + public FrameMetricsWrapper mMetricsWrapper; + + private Session mSession; + + public FrameTracker(@NonNull Session session, + @NonNull Handler handler, @NonNull ThreadedRenderer renderer) { + mSession = session; + mRendererWrapper = new ThreadedRendererWrapper(renderer); + mMetricsWrapper = new FrameMetricsWrapper(); + mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler); + } + + /** + * This constructor is only for unit tests. + * @param session a trace session. + * @param renderer a test double for ThreadedRenderer + * @param metrics a test double for FrameMetrics + */ + @VisibleForTesting + public FrameTracker(@NonNull Session session, Handler handler, + @NonNull ThreadedRendererWrapper renderer, @NonNull FrameMetricsWrapper metrics) { + mSession = session; + mRendererWrapper = renderer; + mMetricsWrapper = metrics; + mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler); + } + + /** + * Begin a trace session of the CUJ. + */ + public void begin() { + long timestamp = System.nanoTime(); + if (DEBUG) { + Log.d(TAG, "begin: time(ns)=" + timestamp + ", begin(ns)=" + mBeginTime + + ", end(ns)=" + mEndTime + ", session=" + mSession); + } + if (mBeginTime != UNKNOWN_TIMESTAMP && mEndTime == UNKNOWN_TIMESTAMP) { + // We have an ongoing tracing already, skip subsequent calls. + return; + } + mBeginTime = timestamp; + mEndTime = UNKNOWN_TIMESTAMP; + Trace.beginAsyncSection(mSession.getName(), (int) mBeginTime); + mRendererWrapper.addObserver(mObserver); + } + + /** + * End the trace session of the CUJ. + */ + public void end() { + long timestamp = System.nanoTime(); + if (DEBUG) { + Log.d(TAG, "end: time(ns)=" + timestamp + ", begin(ns)=" + mBeginTime + + ", end(ns)=" + mEndTime + ", session=" + mSession); + } + if (mBeginTime == UNKNOWN_TIMESTAMP || mEndTime != UNKNOWN_TIMESTAMP) { + // We haven't started a trace yet. + return; + } + mEndTime = timestamp; + Trace.endAsyncSection(mSession.getName(), (int) mBeginTime); + } + + /** + * Check if we had a janky frame according to the metrics. + * @param metrics frame metrics + * @return true if it is a janky frame + */ + @VisibleForTesting + public boolean isJankyFrame(FrameMetricsWrapper metrics) { + long totalDurationMs = metrics.getMetric(FrameMetrics.TOTAL_DURATION); + boolean isFirstFrame = metrics.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1; + boolean isJanky = !isFirstFrame && totalDurationMs - CRITERIA > 0; + + if (DEBUG) { + StringBuilder sb = new StringBuilder(); + sb.append(isJanky).append(","); + sb.append(metrics.getMetric(FrameMetrics.FIRST_DRAW_FRAME)).append(","); + sb.append(metrics.getMetric(FrameMetrics.INPUT_HANDLING_DURATION)).append(","); + sb.append(metrics.getMetric(FrameMetrics.ANIMATION_DURATION)).append(","); + sb.append(metrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION)).append(","); + sb.append(metrics.getMetric(FrameMetrics.DRAW_DURATION)).append(","); + sb.append(metrics.getMetric(FrameMetrics.SYNC_DURATION)).append(","); + sb.append(metrics.getMetric(FrameMetrics.COMMAND_ISSUE_DURATION)).append(","); + sb.append(metrics.getMetric(FrameMetrics.SWAP_BUFFERS_DURATION)).append(","); + sb.append(totalDurationMs).append(","); + sb.append(metrics.getMetric(FrameMetrics.INTENDED_VSYNC_TIMESTAMP)).append(","); + sb.append(metrics.getMetric(FrameMetrics.VSYNC_TIMESTAMP)).append(","); + Log.v(TAG, "metrics=" + sb.toString()); + } + + return isJanky; + } + + @Override + public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) { + // Since this callback might come a little bit late after the end() call. + // We should keep tracking the begin / end timestamp. + // Then compare with vsync timestamp to check if the frame is in the duration of the CUJ. + + if (mBeginTime == UNKNOWN_TIMESTAMP) return; // We haven't started tracing yet. + long vsyncTimestamp = mMetricsWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP); + if (vsyncTimestamp < mBeginTime) return; // The tracing has been started. + + // If the end time has not been set, we are still in the tracing. + if (mEndTime != UNKNOWN_TIMESTAMP && vsyncTimestamp > mEndTime) { + // The tracing has been ended, remove the observer, see if need to trigger perfetto. + mRendererWrapper.removeObserver(mObserver); + // Trigger perfetto if necessary. + if (mShouldTriggerTrace) { + if (DEBUG) { + Log.v(TAG, "Found janky frame, triggering perfetto."); + } + triggerPerfetto(); + } + return; + } + + // The frame is in the duration of the CUJ, check if it catches the deadline. + if (isJankyFrame(mMetricsWrapper)) { + mShouldTriggerTrace = true; + } + } + + /** + * Trigger the prefetto daemon. + */ + @VisibleForTesting + public void triggerPerfetto() { + InteractionJankMonitor.trigger(); + } + + /** + * A wrapper class that we can spy FrameMetrics (a final class) in unit tests. + */ + public static class FrameMetricsWrapper { + private FrameMetrics mFrameMetrics; + + public FrameMetricsWrapper() { + mFrameMetrics = new FrameMetrics(); + } + + /** + * Wrapper method. + * @return timing data of the metrics + */ + public long[] getTiming() { + return mFrameMetrics.mTimingData; + } + + /** + * Wrapper method. + * @param index specific index of the timing data + * @return the timing data of the specified index + */ + public long getMetric(int index) { + return mFrameMetrics.getMetric(index); + } + } + + /** + * A wrapper class that we can spy ThreadedRenderer (a final class) in unit tests. + */ + public static class ThreadedRendererWrapper { + private ThreadedRenderer mRenderer; + + public ThreadedRendererWrapper(ThreadedRenderer renderer) { + mRenderer = renderer; + } + + /** + * Wrapper method. + * @param observer observer + */ + public void addObserver(HardwareRendererObserver observer) { + mRenderer.addObserver(observer); + } + + /** + * Wrapper method. + * @param observer observer + */ + public void removeObserver(HardwareRendererObserver observer) { + mRenderer.removeObserver(observer); + } + } +} diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java new file mode 100644 index 000000000000..6bfb178bc102 --- /dev/null +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -0,0 +1,181 @@ +/* + * 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.jank; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.HandlerThread; +import android.view.ThreadedRenderer; +import android.view.View; + +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.HashMap; +import java.util.Map; + +/** + * This class let users to begin and end the always on tracing mechanism. + * @hide + */ +public class InteractionJankMonitor { + private static final String TAG = InteractionJankMonitor.class.getSimpleName(); + private static final boolean DEBUG = false; + private static final Object LOCK = new Object(); + public static final int CUJ_NOTIFICATION_SHADE_MOTION = 0; + public static final int CUJ_NOTIFICATION_SHADE_GESTURE = 1; + + private static ThreadedRenderer sRenderer; + private static Map<String, FrameTracker> sRunningTracker; + private static HandlerThread sWorker; + private static boolean sInitialized; + + /** @hide */ + @IntDef({ + CUJ_NOTIFICATION_SHADE_MOTION, + CUJ_NOTIFICATION_SHADE_GESTURE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CujType {} + + /** + * @param view Any view in the view tree to get context and ThreadedRenderer. + */ + public static void init(@NonNull View view) { + init(view, null, null, null); + } + + /** + * Should be only invoked internally or from unit tests. + */ + @VisibleForTesting + public static void init(@NonNull View view, @NonNull ThreadedRenderer renderer, + @NonNull Map<String, FrameTracker> map, @NonNull HandlerThread worker) { + //TODO (163505250): This should be no-op if not in droid food rom. + synchronized (LOCK) { + if (!sInitialized) { + if (!view.isAttachedToWindow()) { + throw new IllegalStateException("View is not attached!"); + } + sRenderer = renderer == null ? view.getThreadedRenderer() : renderer; + sRunningTracker = map == null ? new HashMap<>() : map; + sWorker = worker == null ? new HandlerThread("Aot-Worker") : worker; + sWorker.start(); + sInitialized = true; + } + } + } + + /** + * Must invoke init() before invoking this method. + */ + public static void begin(@NonNull @CujType int cujType) { + begin(cujType, null); + } + + /** + * Should be only invoked internally or from unit tests. + */ + @VisibleForTesting + public static void begin(@NonNull @CujType int cujType, FrameTracker tracker) { + //TODO (163505250): This should be no-op if not in droid food rom. + //TODO (163510843): Remove synchronized, add @UiThread if only invoked from ui threads. + synchronized (LOCK) { + checkInitStateLocked(); + Session session = new Session(cujType); + FrameTracker currentTracker = getTracker(session.getName()); + if (currentTracker != null) return; + if (tracker == null) { + tracker = new FrameTracker(session, sWorker.getThreadHandler(), sRenderer); + } + sRunningTracker.put(session.getName(), tracker); + tracker.begin(); + } + } + + /** + * Must invoke init() before invoking this method. + */ + public static void end(@NonNull @CujType int cujType) { + //TODO (163505250): This should be no-op if not in droid food rom. + //TODO (163510843): Remove synchronized, add @UiThread if only invoked from ui threads. + synchronized (LOCK) { + checkInitStateLocked(); + Session session = new Session(cujType); + FrameTracker tracker = getTracker(session.getName()); + if (tracker != null) { + tracker.end(); + sRunningTracker.remove(session.getName()); + } + } + } + + private static void checkInitStateLocked() { + if (!sInitialized) { + throw new IllegalStateException("InteractionJankMonitor not initialized!"); + } + } + + /** + * Should be only invoked from unit tests. + */ + @VisibleForTesting + public static void reset() { + sInitialized = false; + sRenderer = null; + sRunningTracker = null; + if (sWorker != null) { + sWorker.quit(); + sWorker = null; + } + } + + private static FrameTracker getTracker(String sessionName) { + synchronized (LOCK) { + return sRunningTracker.get(sessionName); + } + } + + /** + * Trigger the perfetto daemon to collect and upload data. + */ + public static void trigger() { + sWorker.getThreadHandler().post( + () -> PerfettoTrigger.trigger(PerfettoTrigger.TRIGGER_TYPE_JANK)); + } + + /** + * A class to represent a session. + */ + public static class Session { + private @CujType int mId; + + public Session(@CujType int session) { + mId = session; + } + + public int getId() { + return mId; + } + + public String getName() { + return "CujType<" + mId + ">"; + } + } + +} diff --git a/core/java/com/android/internal/jank/PerfettoTrigger.java b/core/java/com/android/internal/jank/PerfettoTrigger.java new file mode 100644 index 000000000000..6c8d3cdcf5ae --- /dev/null +++ b/core/java/com/android/internal/jank/PerfettoTrigger.java @@ -0,0 +1,115 @@ +/* + * 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. + */ + +//TODO (165884885): Make PerfettoTrigger more generic and move it to another package. +package com.android.internal.jank; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A trigger implementation with perfetto backend. + * @hide + */ +public class PerfettoTrigger { + private static final String TAG = PerfettoTrigger.class.getSimpleName(); + private static final boolean DEBUG = false; + private static final String TRIGGER_COMMAND = "/system/bin/trigger_perfetto"; + private static final String[] TRIGGER_TYPE_NAMES = new String[] { "jank-tracker" }; + public static final int TRIGGER_TYPE_JANK = 0; + + /** @hide */ + @IntDef({ + TRIGGER_TYPE_JANK + }) + @Retention(RetentionPolicy.SOURCE) + public @interface TriggerType {} + + /** + * @param type the trigger type + */ + public static void trigger(@NonNull @TriggerType int type) { + try { + Token token = new Token(type, TRIGGER_TYPE_NAMES[type]); + ProcessBuilder pb = new ProcessBuilder(TRIGGER_COMMAND, token.getName()); + if (DEBUG) { + StringBuilder sb = new StringBuilder(); + for (String arg : pb.command()) { + sb.append(arg).append(" "); + } + Log.d(TAG, "Triggering " + sb.toString()); + } + Process process = pb.start(); + if (DEBUG) { + readConsoleOutput(process); + } + } catch (IOException | InterruptedException e) { + Log.w(TAG, "Failed to trigger " + type, e); + } + } + + private static void readConsoleOutput(@NonNull Process process) + throws IOException, InterruptedException { + process.waitFor(); + try (BufferedReader errReader = + new BufferedReader(new InputStreamReader(process.getErrorStream()))) { + StringBuilder errLine = new StringBuilder(); + String line; + while ((line = errReader.readLine()) != null) { + errLine.append(line).append("\n"); + } + errLine.append(", code=").append(process.exitValue()); + Log.d(TAG, "err message=" + errLine.toString()); + } + } + + /** + * Token which is used to trigger perfetto. + */ + public static class Token { + private int mType; + private String mName; + + Token(@TriggerType int type, String name) { + mType = type; + mName = name; + } + + /** + * Get trigger type. + * @return trigger type, should be @TriggerType + */ + public int getType() { + return mType; + } + + /** + * Get name of this token as the argument while triggering perfetto. + * @return name + */ + public String getName() { + return mName; + } + } + +} diff --git a/core/java/com/android/internal/view/ScrollCaptureViewHelper.java b/core/java/com/android/internal/view/ScrollCaptureViewHelper.java index 9f100bd6440f..a92e978b2fc1 100644 --- a/core/java/com/android/internal/view/ScrollCaptureViewHelper.java +++ b/core/java/com/android/internal/view/ScrollCaptureViewHelper.java @@ -26,6 +26,36 @@ interface ScrollCaptureViewHelper<V extends View> { int DOWN = 1; /** + * Contains the result of a scroll request. + */ + class ScrollResult { + /** + * The area requested in pixels, within {@link #onComputeScrollBounds scroll bounds}, with + * top/bottom relative to the scroll position at the start of capture. + */ + public Rect requestedArea; + /** + * The area, in pixels of the request which is visible and available for capture. In the + * same coordinate space as {@link #requestedArea}. + */ + public Rect availableArea; + /** + * The updated scroll delta (the relative distance, in pixels that the scroll position has + * moved from the starting position since capture started). + */ + public int scrollDelta; // visible top offset from start + + @Override + public String toString() { + return "ScrollResult{" + + "requestedArea=" + requestedArea + + ", availableArea=" + availableArea + + ", scrollDelta=" + scrollDelta + + '}'; + } + } + + /** * Verifies that the view is still visible and scrollable. If true is returned here, expect a * call to {@link #onComputeScrollBounds(View)} to follow. * @@ -48,6 +78,7 @@ interface ScrollCaptureViewHelper<V extends View> { view.getWidth() - view.getPaddingRight(), view.getHeight() - view.getPaddingBottom()); } + /** * Adjust the target for capture. * <p> @@ -67,14 +98,14 @@ interface ScrollCaptureViewHelper<V extends View> { * needed and return the resulting rectangle describing the position and bounds of the area * which is visible. * + * @param view the view being captured * @param scrollBounds the area in which scrolling content moves, local to the {@code containing * view} * @param requestRect the area relative to {@code scrollBounds} which describes the location of * content to capture for the request - * @return the visible area within scrollBounds of the requested rectangle, return {@code null} - * in the case of an unrecoverable error condition, to abort the capture process + * @return the result of the request as a {@link ScrollResult} */ - Rect onScrollRequested(@NonNull V view, Rect scrollBounds, Rect requestRect); + ScrollResult onScrollRequested(@NonNull V view, Rect scrollBounds, Rect requestRect); /** * Restore the target after capture. diff --git a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java index 4087eda944e0..7b4f73ffde2b 100644 --- a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java +++ b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java @@ -30,21 +30,24 @@ import android.view.ScrollCaptureSession; import android.view.Surface; import android.view.View; +import com.android.internal.view.ScrollCaptureViewHelper.ScrollResult; + import java.lang.ref.WeakReference; import java.util.function.Consumer; /** - * Provides a ScrollCaptureCallback implementation for to handle arbitrary View-based scrolling - * containers. - * <p> - * To use this class, supply the target view and an implementation of {@ScrollCaptureViewHelper} - * to the callback. + * Provides a base ScrollCaptureCallback implementation to handle arbitrary View-based scrolling + * containers. This class handles the bookkeeping aspects of {@link ScrollCaptureCallback} + * including rendering output using HWUI. Adaptable to any {@link View} using + * {@link ScrollCaptureViewHelper}. * * @param <V> the specific View subclass handled - * @hide + * @see ScrollCaptureViewHelper */ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCallback { + private static final String TAG = "ScrollCaptureViewSupport"; + private final WeakReference<V> mWeakView; private final ScrollCaptureViewHelper<V> mViewHelper; private ViewRenderer mRenderer; @@ -52,11 +55,6 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa private boolean mStarted; private boolean mEnded; - static <V extends View> ScrollCaptureCallback createCallback(V view, - ScrollCaptureViewHelper<V> impl) { - return new ScrollCaptureViewSupport<>(view, impl); - } - ScrollCaptureViewSupport(V containingView, ScrollCaptureViewHelper<V> viewHelper) { mWeakView = new WeakReference<>(containingView); mRenderer = new ViewRenderer(); @@ -82,6 +80,7 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa @Override public final void onScrollCaptureStart(ScrollCaptureSession session, Runnable onReady) { V view = mWeakView.get(); + mEnded = false; mStarted = true; @@ -103,21 +102,30 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa session.notifyBufferSent(0, null); return; } - Rect captureArea = mViewHelper.onScrollRequested(view, session.getScrollBounds(), + // Ask the view to scroll as needed to bring this area into view. + ScrollResult scrollResult = mViewHelper.onScrollRequested(view, session.getScrollBounds(), requestRect); - mRenderer.renderFrame(view, captureArea, mUiHandler, - () -> session.notifyBufferSent(0, captureArea)); + view.invalidate(); // don't wait for vsync + + // For image capture, shift back by scrollDelta to arrive at the location within the view + // where the requested content will be drawn + Rect viewCaptureArea = new Rect(scrollResult.availableArea); + viewCaptureArea.offset(0, -scrollResult.scrollDelta); + + mRenderer.renderView(view, viewCaptureArea, mUiHandler, + (frameNumber) -> session.notifyBufferSent(frameNumber, scrollResult.availableArea)); } @Override public final void onScrollCaptureEnd(Runnable onReady) { V view = mWeakView.get(); if (mStarted && !mEnded) { - mViewHelper.onPrepareForEnd(view); - /* empty */ + if (view != null) { + mViewHelper.onPrepareForEnd(view); + view.invalidate(); + } mEnded = true; - mRenderer.trimMemory(); - mRenderer.setSurface(null); + mRenderer.destroy(); } onReady.run(); } @@ -142,7 +150,7 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa private static final String TAG = "ViewRenderer"; private HardwareRenderer mRenderer; - private RenderNode mRootRenderNode; + private RenderNode mCaptureRenderNode; private final RectF mTempRectF = new RectF(); private final Rect mSourceRect = new Rect(); private final Rect mTempRect = new Rect(); @@ -151,10 +159,14 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa private long mLastRenderedSourceDrawingId = -1; + public interface FrameCompleteListener { + void onFrameComplete(long frameNumber); + } + ViewRenderer() { mRenderer = new HardwareRenderer(); - mRootRenderNode = new RenderNode("ScrollCaptureRoot"); - mRenderer.setContentRoot(mRootRenderNode); + mCaptureRenderNode = new RenderNode("ScrollCaptureRoot"); + mRenderer.setContentRoot(mCaptureRenderNode); // TODO: Figure out a way to flip this on when we are sure the source window is opaque mRenderer.setOpaque(false); @@ -193,18 +205,36 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa // Enable shadows for elevation/Z mRenderer.setLightSourceGeometry(lightX, lightY, lightZ, lightRadius); mRenderer.setLightSourceAlpha(AMBIENT_SHADOW_ALPHA, SPOT_SHADOW_ALPHA); + } + + private void updateRootNode(View source, Rect localSourceRect) { + final View rootView = source.getRootView(); + transformToRoot(source, localSourceRect, mTempRect); + + mCaptureRenderNode.setPosition(0, 0, mTempRect.width(), mTempRect.height()); + RecordingCanvas canvas = mCaptureRenderNode.beginRecording(); + canvas.enableZ(); + canvas.translate(-mTempRect.left, -mTempRect.top); + RenderNode rootViewRenderNode = rootView.updateDisplayListIfDirty(); + if (rootViewRenderNode.hasDisplayList()) { + canvas.drawRenderNode(rootViewRenderNode); + } + mCaptureRenderNode.endRecording(); } - public void renderFrame(View localReference, Rect sourceRect, Handler handler, - Runnable onFrameCommitted) { - if (updateForView(localReference)) { - setupLighting(localReference); + public void renderView(View view, Rect sourceRect, Handler handler, + FrameCompleteListener frameListener) { + if (updateForView(view)) { + setupLighting(view); } - buildRootDisplayList(localReference, sourceRect); + view.invalidate(); + updateRootNode(view, sourceRect); HardwareRenderer.FrameRenderRequest request = mRenderer.createRenderRequest(); request.setVsyncTime(SystemClock.elapsedRealtimeNanos()); - request.setFrameCommitCallback(handler::post, onFrameCommitted); + // private API b/c request.setFrameCommitCallback does not provide access to frameNumber + mRenderer.setFrameCompleteCallback( + frameNr -> handler.post(() -> frameListener.onFrameComplete(frameNr))); request.setWaitForPresent(true); request.syncAndDraw(); } @@ -225,15 +255,5 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa mTempRectF.round(outRect); } - private void buildRootDisplayList(View source, Rect localSourceRect) { - final View captureSource = source.getRootView(); - transformToRoot(source, localSourceRect, mTempRect); - mRootRenderNode.setPosition(0, 0, mTempRect.width(), mTempRect.height()); - RecordingCanvas canvas = mRootRenderNode.beginRecording(mTempRect.width(), - mTempRect.height()); - canvas.translate(-mTempRect.left, -mTempRect.top); - canvas.drawRenderNode(captureSource.updateDisplayListIfDirty()); - mRootRenderNode.endRecording(); - } } } diff --git a/core/java/com/android/internal/view/ScrollViewCaptureHelper.java b/core/java/com/android/internal/view/ScrollViewCaptureHelper.java index 12bd461f810b..1514b9a285dd 100644 --- a/core/java/com/android/internal/view/ScrollViewCaptureHelper.java +++ b/core/java/com/android/internal/view/ScrollViewCaptureHelper.java @@ -35,13 +35,14 @@ import android.view.ViewParent; * <li>correctly implements {@link ViewParent#requestChildRectangleOnScreen(View, * Rect, boolean)} * </ul> + * + * @see ScrollCaptureViewSupport */ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGroup> { private int mStartScrollY; private boolean mScrollBarEnabled; private int mOverScrollMode; - /** @see ScrollCaptureViewHelper#onPrepareForStart(View, Rect) */ public void onPrepareForStart(@NonNull ViewGroup view, Rect scrollBounds) { mStartScrollY = view.getScrollY(); mOverScrollMode = view.getOverScrollMode(); @@ -54,8 +55,8 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou } } - /** @see ScrollCaptureViewHelper#onScrollRequested(View, Rect, Rect) */ - public Rect onScrollRequested(@NonNull ViewGroup view, Rect scrollBounds, Rect requestRect) { + public ScrollResult onScrollRequested(@NonNull ViewGroup view, Rect scrollBounds, + Rect requestRect) { final View contentView = view.getChildAt(0); // returns null, does not throw IOOBE if (contentView == null) { return null; @@ -87,6 +88,9 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou \__ Requested Bounds[0,300 - 200,400] (200x100) */ + ScrollResult result = new ScrollResult(); + result.requestedArea = new Rect(requestRect); + // 0) adjust the requestRect to account for scroll change since start // // Scroll Bounds[50,50 - 250,250] (w=200,h=200) @@ -117,8 +121,6 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou view.getScrollX() - contentView.getLeft(), view.getScrollY() - contentView.getTop()); - - // requestRect is now local to contentView as requestedContentBounds // contentView (and each parent in turn if possible) will be scrolled // (if necessary) to make all of requestedContent visible, (if possible!) @@ -126,35 +128,37 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou // update new offset between starting and current scroll position scrollDelta = view.getScrollY() - mStartScrollY; + result.scrollDelta = scrollDelta; - - // TODO: adjust to avoid occlusions/minimize scroll changes + // TODO: crop capture area to avoid occlusions/minimize scroll changes Point offset = new Point(); - final Rect capturedRect = new Rect(requestedContentBounds); // empty - if (!view.getChildVisibleRect(contentView, capturedRect, offset)) { - capturedRect.setEmpty(); - return capturedRect; + final Rect available = new Rect(requestedContentBounds); // empty + if (!view.getChildVisibleRect(contentView, available, offset)) { + available.setEmpty(); + result.availableArea = available; + return result; } // Transform back from global to content-view local - capturedRect.offset(-offset.x, -offset.y); + available.offset(-offset.x, -offset.y); // Then back to container view - capturedRect.offset( + available.offset( contentView.getLeft() - view.getScrollX(), contentView.getTop() - view.getScrollY()); // And back to relative to scrollBounds - capturedRect.offset(-scrollBounds.left, -scrollBounds.top); + available.offset(-scrollBounds.left, -scrollBounds.top); - // Apply scrollDelta again to return to make capturedRect relative to scrollBounds at + // Apply scrollDelta again to return to make `available` relative to `scrollBounds` at // the scroll position at start of capture. - capturedRect.offset(0, scrollDelta); - return capturedRect; + available.offset(0, scrollDelta); + + result.availableArea = new Rect(available); + return result; } - /** @see ScrollCaptureViewHelper#onPrepareForEnd(View) */ public void onPrepareForEnd(@NonNull ViewGroup view) { view.scrollTo(0, mStartScrollY); if (mOverScrollMode != View.OVER_SCROLL_NEVER) { diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 5c045b65be22..7a5c38385f32 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -20,6 +20,7 @@ #include "android_media_AudioTrack.h" #include <nativehelper/JNIHelp.h> +#include <nativehelper/ScopedUtfChars.h> #include "core_jni_helpers.h" #include <utils/Log.h> @@ -251,7 +252,7 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession, jlong nativeAudioTrack, jboolean offload, jint encapsulationMode, - jobject tunerConfiguration) { + jobject tunerConfiguration, jstring opPackageName) { ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d," " nativeAudioTrack=0x%" PRIX64 ", offload=%d encapsulationMode=%d tuner=%p", jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes, @@ -337,7 +338,8 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we } // create the native AudioTrack object - lpTrack = new AudioTrack(); + ScopedUtfChars opPackageNameStr(env, opPackageName); + lpTrack = new AudioTrack(opPackageNameStr.c_str()); // read the AudioAttributes values auto paa = JNIAudioAttributeHelper::makeUnique(); @@ -371,23 +373,24 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we status_t status = NO_ERROR; switch (memoryMode) { case MODE_STREAM: - status = lpTrack->set( - AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument) - sampleRateInHertz, - format,// word length, PCM - nativeChannelMask, - offload ? 0 : frameCount, - offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_NONE, - audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user) - 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack - 0,// shared mem - true,// thread can call Java - sessionId,// audio session ID - offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC, - offload ? &offloadInfo : NULL, - -1, -1, // default uid, pid values - paa.get()); - + status = lpTrack->set(AUDIO_STREAM_DEFAULT, // stream type, but more info conveyed + // in paa (last argument) + sampleRateInHertz, + format, // word length, PCM + nativeChannelMask, offload ? 0 : frameCount, + offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD + : AUDIO_OUTPUT_FLAG_NONE, + audioCallback, + &(lpJniStorage->mCallbackData), // callback, callback data (user) + 0, // notificationFrames == 0 since not using EVENT_MORE_DATA + // to feed the AudioTrack + 0, // shared mem + true, // thread can call Java + sessionId, // audio session ID + offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK + : AudioTrack::TRANSFER_SYNC, + offload ? &offloadInfo : NULL, -1, -1, // default uid, pid values + paa.get()); break; case MODE_STATIC: @@ -398,22 +401,22 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we goto native_init_failure; } - status = lpTrack->set( - AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument) - sampleRateInHertz, - format,// word length, PCM - nativeChannelMask, - frameCount, - AUDIO_OUTPUT_FLAG_NONE, - audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)); - 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack - lpJniStorage->mMemBase,// shared mem - true,// thread can call Java - sessionId,// audio session ID - AudioTrack::TRANSFER_SHARED, - NULL, // default offloadInfo - -1, -1, // default uid, pid values - paa.get()); + status = lpTrack->set(AUDIO_STREAM_DEFAULT, // stream type, but more info conveyed + // in paa (last argument) + sampleRateInHertz, + format, // word length, PCM + nativeChannelMask, frameCount, AUDIO_OUTPUT_FLAG_NONE, + audioCallback, + &(lpJniStorage->mCallbackData), // callback, callback data (user) + 0, // notificationFrames == 0 since not using EVENT_MORE_DATA + // to feed the AudioTrack + lpJniStorage->mMemBase, // shared mem + true, // thread can call Java + sessionId, // audio session ID + AudioTrack::TRANSFER_SHARED, + NULL, // default offloadInfo + -1, -1, // default uid, pid values + paa.get()); break; default: @@ -1428,7 +1431,8 @@ static const JNINativeMethod gMethods[] = { {"native_stop", "()V", (void *)android_media_AudioTrack_stop}, {"native_pause", "()V", (void *)android_media_AudioTrack_pause}, {"native_flush", "()V", (void *)android_media_AudioTrack_flush}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;)I", + {"native_setup", + "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;Ljava/lang/String;)I", (void *)android_media_AudioTrack_setup}, {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize}, {"native_release", "()V", (void *)android_media_AudioTrack_release}, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 57c1fcf7bfb4..cdcb24b6a247 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/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 34e6efb2bf78..fcf9b837cfa1 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1261,7 +1261,7 @@ <string name="volume_ringtone" msgid="134784084629229029">"Hlasitost vyzvánění"</string> <string name="volume_music" msgid="7727274216734955095">"Hlasitost médií"</string> <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Přehrávání pomocí rozhraní Bluetooth"</string> - <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Je nastaven tichý vyzváněcí tón"</string> + <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Je nastaven tichý vyzvánění"</string> <string name="volume_call" msgid="7625321655265747433">"Hlasitost hovoru"</string> <string name="volume_bluetooth_call" msgid="2930204618610115061">"Hlasitost příchozích hovorů při připojení Bluetooth"</string> <string name="volume_alarm" msgid="4486241060751798448">"Hlasitost budíku"</string> @@ -1272,10 +1272,10 @@ <string name="volume_icon_description_incall" msgid="4491255105381227919">"Hlasitost hovoru"</string> <string name="volume_icon_description_media" msgid="4997633254078171233">"Hlasitost médií"</string> <string name="volume_icon_description_notification" msgid="579091344110747279">"Hlasitost oznámení"</string> - <string name="ringtone_default" msgid="9118299121288174597">"Výchozí vyzváněcí tón"</string> + <string name="ringtone_default" msgid="9118299121288174597">"Výchozí vyzvánění"</string> <string name="ringtone_default_with_actual" msgid="2709686194556159773">"Výchozí (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> <string name="ringtone_silent" msgid="397111123930141876">"Žádný"</string> - <string name="ringtone_picker_title" msgid="667342618626068253">"Vyzváněcí tóny"</string> + <string name="ringtone_picker_title" msgid="667342618626068253">"Vyzvánění"</string> <string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"Zvuky budíku"</string> <string name="ringtone_picker_title_notification" msgid="6387191794719608122">"Zvuky upozornění"</string> <string name="ringtone_unknown" msgid="5059495249862816475">"Neznámé"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 117fecb0ffd0..0b7e396839ef 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -657,7 +657,7 @@ <string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"observer netværksforhold"</string> <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Tillader, at en applikation observerer netværksforhold. Bør aldrig være nødvendigt for almindelige apps."</string> <string name="permlab_setInputCalibration" msgid="932069700285223434">"skift kalibrering for inputenheden"</string> - <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"Tillader, at appen ændrer kalibreringsparametrene for berøringsskærmen. Dette bør aldrig være nødvendigt for almindelige apps."</string> + <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"Tillader, at appen ændrer kalibreringsparametrene for touchskærmen. Dette bør aldrig være nødvendigt for almindelige apps."</string> <string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"få adgang til DRM-certifikater"</string> <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"Tillader, at en applikation provisionerer og anvender DRM-certifikater. Dette bør aldrig være nødvendigt for almindelige apps."</string> <string name="permlab_handoverStatus" msgid="7620438488137057281">"modtag status for Android Beam-overførsler"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index ecce980c613f..c93dbbfda5ef 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -484,8 +484,8 @@ <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"Telefonoaren ordu-zona aldatzeko baimena ematen die aplikazioei."</string> <string name="permlab_getAccounts" msgid="5304317160463582791">"bilatu gailuko kontuak"</string> <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"Tabletak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dauzkazun aplikazioek sortutako kontuak har daitezke barnean."</string> - <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Android TV gailuak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Kontu horien artean, instalatuta dituzun aplikazioek sortutako kontuak egon litezke."</string> - <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Telefonoak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dituzun aplikazioek sortutako kontuak har daitezke barnean."</string> + <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Android TV gailuak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Kontu horien artean, instalatuta dauzkazun aplikazioek sortutako kontuak egon litezke."</string> + <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Telefonoak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dauzkazun aplikazioek sortutako kontuak har daitezke barnean."</string> <string name="permlab_accessNetworkState" msgid="2349126720783633918">"ikusi sareko konexioak"</string> <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Sareko konexioei buruzko informazioa ikusteko baimena ematen die aplikazioei; adibidez, zer sare dauden eta zeintzuk dauden konektatuta."</string> <string name="permlab_createNetworkSockets" msgid="3224420491603590541">"izan sarerako sarbide osoa"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index f9e3e2fa97e7..f4fb83deba39 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -2035,7 +2035,7 @@ <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Aplikasi ini tidak diberi izin merekam, tetapi dapat merekam audio melalui perangkat USB ini."</string> <string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Beranda"</string> <string name="accessibility_system_action_back_label" msgid="4205361367345537608">"Kembali"</string> - <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Aplikasi yang Baru Dipakai"</string> + <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Aplikasi Terbaru"</string> <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"Notifikasi"</string> <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Setelan Cepat"</string> <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Dialog Daya"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index bb79c2193a36..ee0362e4a184 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -304,13 +304,13 @@ <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS सन्देशहरू पठाउनुहोस् र हेर्नुहोस्"</string> <string name="permgrouplab_storage" msgid="1938416135375282333">"फाइल र मिडिया"</string> - <string name="permgroupdesc_storage" msgid="6351503740613026600">"तपाईंको यन्त्रमा तस्बिर, मिडिया, र फाइलहरूमाथि पहुँच गर्नुहोस्"</string> + <string name="permgroupdesc_storage" msgid="6351503740613026600">"तपाईंको यन्त्रमा फोटो, मिडिया, र फाइलहरूमाथि पहुँच गर्नुहोस्"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"माइक्रोफोन"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"अडियो रेकर्ड गर्नुहोस्"</string> <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"शारीरिक क्रियाकलाप"</string> <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"आफ्नो शारीरिक क्रियाकलापको डेटामाथि पहुँच राख्नु"</string> <string name="permgrouplab_camera" msgid="9090413408963547706">"क्यामेरा"</string> - <string name="permgroupdesc_camera" msgid="7585150538459320326">"तस्बिर खिच्नुका साथै भिडियो रेकर्ड गर्नुहोस्"</string> + <string name="permgroupdesc_camera" msgid="7585150538459320326">"फोटो खिच्नुका साथै भिडियो रेकर्ड गर्नुहोस्"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"कलका लगहरू"</string> <string name="permgroupdesc_calllog" msgid="2026996642917801803">"फोन कलको लग पढ्नुहोस् र लेख्नुहोस्"</string> <string name="permgrouplab_phone" msgid="570318944091926620">"फोन"</string> @@ -437,10 +437,10 @@ <string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM लाई आदेश पठाउन एपलाई अनुमति दिन्छ। यो निकै खतरनाक हुन्छ।"</string> <string name="permlab_activityRecognition" msgid="1782303296053990884">"शारीरिक गतिविधि पहिचान गर्नुहोस्"</string> <string name="permdesc_activityRecognition" msgid="8667484762991357519">"यो अनुप्रयोगले तपाईंको शारीरिक गतिविधिको पहिचान गर्न सक्छ।"</string> - <string name="permlab_camera" msgid="6320282492904119413">"तस्बिरहरू र भिडियोहरू लिनुहोस्।"</string> - <string name="permdesc_camera" msgid="1354600178048761499">"यस अनुप्रयोगले जुनसुकै समय क्यामेराको प्रयोग गरी तस्बिर खिच्न र भिडियो रेकर्ड गर्न सक्छ।"</string> - <string name="permlab_systemCamera" msgid="3642917457796210580">"एप वा सेवालाई तस्बिर र भिडियो खिच्न प्रणालीका क्यामेराहरूमाथि पहुँच राख्न दिनुहोस्"</string> - <string name="permdesc_systemCamera" msgid="5938360914419175986">"प्रणालीको यस विशेषाधिकार प्राप्त अनुप्रयोगले जुनसुकै बेला प्रणालीको क्यामेरा प्रयोग गरी तस्बिर खिच्न र भिडियो रेकर्ड गर्न सक्छ। अनुप्रयोगसँग पनि android.permission.CAMERA प्रयोग गर्ने अनुमति हुनु पर्छ"</string> + <string name="permlab_camera" msgid="6320282492904119413">"फोटोहरू र भिडियोहरू लिनुहोस्।"</string> + <string name="permdesc_camera" msgid="1354600178048761499">"यस अनुप्रयोगले जुनसुकै समय क्यामेराको प्रयोग गरी फोटो खिच्न र भिडियो रेकर्ड गर्न सक्छ।"</string> + <string name="permlab_systemCamera" msgid="3642917457796210580">"एप वा सेवालाई फोटो र भिडियो खिच्न प्रणालीका क्यामेराहरूमाथि पहुँच राख्न दिनुहोस्"</string> + <string name="permdesc_systemCamera" msgid="5938360914419175986">"प्रणालीको यस विशेषाधिकार प्राप्त अनुप्रयोगले जुनसुकै बेला प्रणालीको क्यामेरा प्रयोग गरी फोटो खिच्न र भिडियो रेकर्ड गर्न सक्छ। अनुप्रयोगसँग पनि android.permission.CAMERA प्रयोग गर्ने अनुमति हुनु पर्छ"</string> <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"कुनै एप वा सेवालाई खोलिँदै वा बन्द गरिँदै गरेका क्यामेरा यन्त्रहरूका बारेमा कलब्याक प्राप्त गर्ने अनुमति दिनुहोस्।"</string> <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"कुनै क्यामेरा यन्त्र खोलिँदा (कुन अनुप्रयोगले खोलेको भन्ने बारेमा) वा बन्द गरिँदा यो अनुप्रयोगले कलब्याक प्राप्त गर्न सक्छ।"</string> <string name="permlab_vibrate" msgid="8596800035791962017">"कम्पन नियन्त्रण गर्नुहोस्"</string> @@ -1347,7 +1347,7 @@ <string name="ext_media_new_notification_title" product="automotive" msgid="9085349544984742727">"<xliff:g id="NAME">%s</xliff:g> ले काम गरिरहेको छैन"</string> <string name="ext_media_new_notification_message" msgid="6095403121990786986">"सेटअप गर्न ट्याप गर्नुहोस्"</string> <string name="ext_media_new_notification_message" product="automotive" msgid="5140127881613227162">"तपाईंले यो यन्त्र पुनः फर्म्याट गर्नु पर्ने हुन सक्छ। यो यन्त्र हटाउन ट्याप गर्नुहोस्।"</string> - <string name="ext_media_ready_notification_message" msgid="777258143284919261">"तस्बिरहरू र मिडिया स्थानान्तरणका लागि"</string> + <string name="ext_media_ready_notification_message" msgid="777258143284919261">"फोटोहरू र मिडिया स्थानान्तरणका लागि"</string> <string name="ext_media_unmountable_notification_title" msgid="4895444667278979910">"<xliff:g id="NAME">%s</xliff:g> मा समस्या देखियो"</string> <string name="ext_media_unmountable_notification_title" product="automotive" msgid="3142723758949023280">"<xliff:g id="NAME">%s</xliff:g> ले काम गरिरहेको छैन"</string> <string name="ext_media_unmountable_notification_message" msgid="3256290114063126205">"समस्या समाधान गर्न ट्याप गर्नुहोस्"</string> @@ -1914,7 +1914,7 @@ <string name="app_category_game" msgid="4534216074910244790">"खेलहरू"</string> <string name="app_category_audio" msgid="8296029904794676222">"सङ्गीत तथा अडियो"</string> <string name="app_category_video" msgid="2590183854839565814">"चलचित्र तथा भिडियो"</string> - <string name="app_category_image" msgid="7307840291864213007">"तस्बिर तथा छविहरू"</string> + <string name="app_category_image" msgid="7307840291864213007">"फोटो तथा छविहरू"</string> <string name="app_category_social" msgid="2278269325488344054">"सामाजिक तथा सञ्चार"</string> <string name="app_category_news" msgid="1172762719574964544">"समाचार तथा पत्रिकाहरू"</string> <string name="app_category_maps" msgid="6395725487922533156">"नक्सा तथा नेभिगेसन"</string> diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java new file mode 100644 index 000000000000..7480a200ee4e --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java @@ -0,0 +1,130 @@ +/* + * 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.jank; + +import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_GESTURE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.only; +import static org.mockito.Mockito.verify; + +import android.os.Handler; +import android.view.FrameMetrics; +import android.view.View; +import android.view.ViewAttachTestActivity; + +import androidx.test.filters.SmallTest; +import androidx.test.rule.ActivityTestRule; + +import com.android.internal.jank.FrameTracker.FrameMetricsWrapper; +import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper; +import com.android.internal.jank.InteractionJankMonitor.Session; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.concurrent.TimeUnit; + +@SmallTest +public class FrameTrackerTest { + private ViewAttachTestActivity mActivity; + + @Rule + public ActivityTestRule<ViewAttachTestActivity> mRule = + new ActivityTestRule<>(ViewAttachTestActivity.class); + + private FrameTracker mTracker; + private ThreadedRendererWrapper mRenderer; + private FrameMetricsWrapper mWrapper; + + @Before + public void setup() { + // Prepare an activity for getting ThreadedRenderer later. + mActivity = mRule.getActivity(); + View view = mActivity.getWindow().getDecorView(); + assertThat(view.isAttachedToWindow()).isTrue(); + + Handler handler = mRule.getActivity().getMainThreadHandler(); + mWrapper = Mockito.spy(new FrameMetricsWrapper()); + mRenderer = Mockito.spy(new ThreadedRendererWrapper(view.getThreadedRenderer())); + doNothing().when(mRenderer).addObserver(any()); + doNothing().when(mRenderer).removeObserver(any()); + + Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE); + mTracker = Mockito.spy(new FrameTracker(session, handler, mRenderer, mWrapper)); + doNothing().when(mTracker).triggerPerfetto(); + } + + @Test + public void testIsJankyFrame() { + // We skip the first frame. + doReturn(1L).when(mWrapper).getMetric(FrameMetrics.FIRST_DRAW_FRAME); + doReturn(TimeUnit.MILLISECONDS.toNanos(20L)) + .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION); + assertThat(mTracker.isJankyFrame(mWrapper)).isFalse(); + + // Should exceed the criteria. + doReturn(0L).when(mWrapper).getMetric(FrameMetrics.FIRST_DRAW_FRAME); + doReturn(TimeUnit.MILLISECONDS.toNanos(20L)) + .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION); + assertThat(mTracker.isJankyFrame(mWrapper)).isTrue(); + + // Should be safe. + doReturn(TimeUnit.MILLISECONDS.toNanos(10L)) + .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION); + assertThat(mTracker.isJankyFrame(mWrapper)).isFalse(); + } + + @Test + public void testBeginEnd() { + // assert the initial values + assertThat(mTracker.mBeginTime).isEqualTo(FrameTracker.UNKNOWN_TIMESTAMP); + assertThat(mTracker.mEndTime).isEqualTo(FrameTracker.UNKNOWN_TIMESTAMP); + + // Observer should be only added once in continuous calls. + mTracker.begin(); + mTracker.begin(); + verify(mRenderer, only()).addObserver(any()); + + // assert the values after begin call. + assertThat(mTracker.mBeginTime).isNotEqualTo(FrameTracker.UNKNOWN_TIMESTAMP); + assertThat(mTracker.mEndTime).isEqualTo(FrameTracker.UNKNOWN_TIMESTAMP); + + // simulate the callback during trace session + // assert the isJankyFrame should be invoked as well. + doReturn(System.nanoTime()).when(mWrapper).getMetric(FrameMetrics.VSYNC_TIMESTAMP); + doReturn(true).when(mTracker).isJankyFrame(any()); + mTracker.onFrameMetricsAvailable(0); + verify(mTracker).isJankyFrame(any()); + + // end the trace session, simulate a callback came after the end call. + // assert the end time should be set, the observer should be removed. + // triggerPerfetto should be invoked as well. + mTracker.end(); + doReturn(System.nanoTime()).when(mWrapper).getMetric(FrameMetrics.VSYNC_TIMESTAMP); + assertThat(mTracker.mEndTime).isNotEqualTo(FrameTracker.UNKNOWN_TIMESTAMP); + mTracker.onFrameMetricsAvailable(0); + verify(mRenderer).removeObserver(any()); + verify(mTracker).triggerPerfetto(); + } +} diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java new file mode 100644 index 000000000000..5c0b0c94f6d0 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java @@ -0,0 +1,120 @@ +/* + * 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.jank; + +import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_GESTURE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.verify; + +import android.os.Handler; +import android.os.HandlerThread; +import android.view.View; +import android.view.ViewAttachTestActivity; + +import androidx.test.filters.SmallTest; +import androidx.test.rule.ActivityTestRule; + +import com.android.internal.jank.FrameTracker.FrameMetricsWrapper; +import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper; +import com.android.internal.jank.InteractionJankMonitor.Session; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mockito; +import org.testng.Assert; + +import java.util.HashMap; +import java.util.Map; + +@SmallTest +public class InteractionJankMonitorTest { + private ViewAttachTestActivity mActivity; + private View mView; + private FrameTracker mTracker; + + @Rule + public ActivityTestRule<ViewAttachTestActivity> mRule = + new ActivityTestRule<>(ViewAttachTestActivity.class); + + @Before + public void setup() { + // Prepare an activity for getting ThreadedRenderer later. + mActivity = mRule.getActivity(); + mView = mActivity.getWindow().getDecorView(); + assertThat(mView.isAttachedToWindow()).isTrue(); + + InteractionJankMonitor.reset(); + + // Prepare a FrameTracker to inject. + Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE); + FrameMetricsWrapper wrapper = Mockito.spy(new FrameTracker.FrameMetricsWrapper()); + ThreadedRendererWrapper renderer = + Mockito.spy(new ThreadedRendererWrapper(mView.getThreadedRenderer())); + Handler handler = mActivity.getMainThreadHandler(); + mTracker = Mockito.spy(new FrameTracker(session, handler, renderer, wrapper)); + } + + @Test + public void testBeginEnd() { + // Should throw exception if the view is not attached. + Assert.assertThrows(IllegalStateException.class, + () -> InteractionJankMonitor.init(new View(mActivity))); + + // Verify we init InteractionJankMonitor correctly. + Map<String, FrameTracker> map = new HashMap<>(); + HandlerThread worker = Mockito.spy(new HandlerThread("Aot-test")); + doNothing().when(worker).start(); + InteractionJankMonitor.init(mView, mView.getThreadedRenderer(), map, worker); + verify(worker).start(); + + // Simulate a trace session and see if begin / end are invoked. + Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE); + assertThat(map.get(session.getName())).isNull(); + InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE, mTracker); + verify(mTracker).begin(); + assertThat(map.get(session.getName())).isEqualTo(mTracker); + InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE); + verify(mTracker).end(); + assertThat(map.get(session.getName())).isNull(); + } + + @Test + public void testCheckInitState() { + // Should throw exception if invoking begin / end without init invocation. + Assert.assertThrows(IllegalStateException.class, + () -> InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE)); + Assert.assertThrows(IllegalStateException.class, + () -> InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE)); + + // Everything should be fine if invoking init first. + boolean thrown = false; + try { + InteractionJankMonitor.init(mActivity.getWindow().getDecorView()); + InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE); + InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE); + } catch (Exception ex) { + thrown = true; + } finally { + assertThat(thrown).isFalse(); + } + } + +} diff --git a/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java b/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java index 63a68e99b788..ab13fd7d81e0 100644 --- a/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java +++ b/core/tests/coretests/src/com/android/internal/view/ScrollViewCaptureHelperTest.java @@ -21,12 +21,11 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; -import static androidx.test.InstrumentationRegistry.getContext; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.content.Context; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -40,10 +39,12 @@ import android.widget.ScrollView; import android.widget.TextView; import androidx.test.annotation.UiThreadTest; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.internal.view.ScrollCaptureViewHelper.ScrollResult; import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import java.util.Random; @@ -67,28 +68,27 @@ public class ScrollViewCaptureHelperTest { private Random mRandom; - private static float sDensity; - - @BeforeClass - public static void setUpClass() { - sDensity = getContext().getResources().getDisplayMetrics().density; - } + private Context mContext; + private float mDensity; @Before @UiThreadTest public void setUp() { + mContext = InstrumentationRegistry.getInstrumentation().getContext(); + mDensity = mContext.getResources().getDisplayMetrics().density; + mRandom = new Random(); - mParent = new FrameLayout(getContext()); + mParent = new FrameLayout(mContext); - mTarget = new ScrollView(getContext()); + mTarget = new ScrollView(mContext); mParent.addView(mTarget, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); - mContent = new LinearLayout(getContext()); + mContent = new LinearLayout(mContext); mContent.setOrientation(LinearLayout.VERTICAL); mTarget.addView(mContent, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT)); for (int i = 0; i < CHILD_VIEWS; i++) { - TextView view = new TextView(getContext()); + TextView view = new TextView(mContext); view.setText("Child #" + i); view.setTextColor(Color.WHITE); view.setTextSize(30f); @@ -99,7 +99,7 @@ public class ScrollViewCaptureHelperTest { // Window -> Parent -> Target -> Content - mWm = getContext().getSystemService(WindowManager.class); + mWm = mContext.getSystemService(WindowManager.class); // Setup the window that we are going to use mWindowLayoutParams = new WindowManager.LayoutParams(WINDOW_WIDTH, WINDOW_HEIGHT, @@ -123,58 +123,6 @@ public class ScrollViewCaptureHelperTest { svc.onPrepareForStart(mTarget, scrollBounds); } - static void assertEmpty(Rect r) { - if (r != null && !r.isEmpty()) { - fail("Not true that " + r + " is empty"); - } - } - - static void assertContains(Rect parent, Rect child) { - if (!parent.contains(child)) { - fail("Not true that " + parent + " contains " + child); - } - } - - static void assertRectEquals(Rect parent, Rect child) { - if (!parent.equals(child)) { - fail("Not true that " + parent + " is equal to " + child); - } - } - - static Rect getVisibleRect(View v) { - Rect r = new Rect(0, 0, v.getWidth(), v.getHeight()); - v.getLocalVisibleRect(r); - return r; - } - - - static int assertScrollToY(View v, int scrollY) { - v.scrollTo(0, scrollY); - int dest = v.getScrollY(); - assertEquals(scrollY, dest); - return scrollY; - } - - - static void assertCapturedAreaCompletelyVisible(int startScrollY, Rect requestRect, - Rect localVisibleNow) { - Rect captured = new Rect(localVisibleNow); - captured.offset(0, -startScrollY); // make relative - - if (!captured.contains(requestRect)) { - fail("Not true that all of " + requestRect + " is contained by " + captured); - } - } - static void assertCapturedAreaPartiallyVisible(int startScrollY, Rect requestRect, - Rect localVisibleNow) { - Rect captured = new Rect(localVisibleNow); - captured.offset(0, -startScrollY); // make relative - - if (!Rect.intersects(captured, requestRect)) { - fail("Not true that any of " + requestRect + " intersects " + captured); - } - } - @Test @UiThreadTest public void onScrollRequested_up_fromTop() { @@ -188,12 +136,13 @@ public class ScrollViewCaptureHelperTest { Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0); - Rect result = svc.onScrollRequested(mTarget, scrollBounds, request); + ScrollResult scrollResult = svc.onScrollRequested(mTarget, + scrollBounds, request); // The result is an empty rectangle and no scrolling, since it // is not possible to physically scroll further up to make the // requested area visible at all (it doesn't exist). - assertEmpty(result); + assertEmpty(scrollResult.availableArea); } @Test @@ -201,7 +150,6 @@ public class ScrollViewCaptureHelperTest { public void onScrollRequested_down_fromTop() { final int startScrollY = assertScrollToY(mTarget, 0); - ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper(); Rect scrollBounds = svc.onComputeScrollBounds(mTarget); svc.onPrepareForStart(mTarget, scrollBounds); @@ -212,13 +160,13 @@ public class ScrollViewCaptureHelperTest { Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(), WINDOW_HEIGHT + CAPTURE_HEIGHT); - Rect result = svc.onScrollRequested(mTarget, scrollBounds, request); - assertRectEquals(request, result); - - assertCapturedAreaCompletelyVisible(startScrollY, request, getVisibleRect(mContent)); + ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request); + assertRectEquals(request, scrollResult.requestedArea); + assertRectEquals(request, scrollResult.availableArea); + assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent)); + assertEquals(CAPTURE_HEIGHT, scrollResult.scrollDelta); } - @Test @UiThreadTest public void onScrollRequested_up_fromMiddle() { @@ -230,12 +178,11 @@ public class ScrollViewCaptureHelperTest { Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0); - - Rect result = svc.onScrollRequested(mTarget, scrollBounds, request); - - assertRectEquals(request, result); - - assertCapturedAreaCompletelyVisible(startScrollY, request, getVisibleRect(mContent)); + ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request); + assertRectEquals(request, scrollResult.requestedArea); + assertRectEquals(request, scrollResult.availableArea); + assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent)); + assertEquals(-CAPTURE_HEIGHT, scrollResult.scrollDelta); } @Test @@ -250,10 +197,12 @@ public class ScrollViewCaptureHelperTest { Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(), WINDOW_HEIGHT + CAPTURE_HEIGHT); - Rect result = svc.onScrollRequested(mTarget, scrollBounds, request); - assertRectEquals(request, result); + ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request); + assertRectEquals(request, scrollResult.requestedArea); + assertRectEquals(request, scrollResult.availableArea); + assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent)); + assertEquals(CAPTURE_HEIGHT, scrollResult.scrollDelta); - assertCapturedAreaCompletelyVisible(startScrollY, request, getVisibleRect(mContent)); } @Test @@ -267,10 +216,11 @@ public class ScrollViewCaptureHelperTest { Rect request = new Rect(0, -CAPTURE_HEIGHT, scrollBounds.width(), 0); - Rect result = svc.onScrollRequested(mTarget, scrollBounds, request); - assertRectEquals(request, result); - - assertCapturedAreaCompletelyVisible(startScrollY, request, getVisibleRect(mContent)); + ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request); + assertRectEquals(request, scrollResult.requestedArea); + assertRectEquals(request, scrollResult.availableArea); + assertRequestedRectCompletelyVisible(startScrollY, request, getVisibleRect(mContent)); + assertEquals(-CAPTURE_HEIGHT, scrollResult.scrollDelta); } @Test @@ -285,12 +235,14 @@ public class ScrollViewCaptureHelperTest { Rect request = new Rect(0, WINDOW_HEIGHT, scrollBounds.width(), WINDOW_HEIGHT + CAPTURE_HEIGHT); - Rect result = svc.onScrollRequested(mTarget, scrollBounds, request); + ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request); + assertRectEquals(request, scrollResult.requestedArea); // The result is an empty rectangle and no scrolling, since it // is not possible to physically scroll further down to make the // requested area visible at all (it doesn't exist). - assertEmpty(result); + assertEmpty(scrollResult.availableArea); + assertEquals(0, scrollResult.scrollDelta); } @Test @@ -309,12 +261,16 @@ public class ScrollViewCaptureHelperTest { 0, top - (CAPTURE_HEIGHT / 2), scrollBounds.width(), top + (CAPTURE_HEIGHT / 2)); - Rect result = svc.onScrollRequested(mTarget, scrollBounds, request); + ScrollResult scrollResult = svc.onScrollRequested(mTarget, scrollBounds, request); + assertRectEquals(request, scrollResult.requestedArea); + + ScrollResult result = svc.onScrollRequested(mTarget, scrollBounds, request); // The result is a partial result Rect expectedResult = new Rect(request); expectedResult.top += 300; // top half clipped - assertRectEquals(expectedResult, result); - assertCapturedAreaPartiallyVisible(startScrollY, request, getVisibleRect(mContent)); + assertRectEquals(expectedResult, result.availableArea); + assertRequestedRectPartiallyVisible(startScrollY, request, getVisibleRect(mContent)); + assertEquals(0, scrollResult.scrollDelta); } @Test @@ -334,13 +290,13 @@ public class ScrollViewCaptureHelperTest { 0, bottom - (CAPTURE_HEIGHT / 2), scrollBounds.width(), bottom + (CAPTURE_HEIGHT / 2)); - Rect result = svc.onScrollRequested(mTarget, scrollBounds, request); + ScrollResult result = svc.onScrollRequested(mTarget, scrollBounds, request); Rect expectedResult = new Rect(request); expectedResult.bottom -= 300; // bottom half clipped - assertRectEquals(expectedResult, result); - assertCapturedAreaPartiallyVisible(startScrollY, request, getVisibleRect(mContent)); - + assertRectEquals(expectedResult, result.availableArea); + assertRequestedRectPartiallyVisible(startScrollY, request, getVisibleRect(mContent)); + assertEquals(0, result.scrollDelta); } @Test @@ -349,4 +305,56 @@ public class ScrollViewCaptureHelperTest { ScrollViewCaptureHelper svc = new ScrollViewCaptureHelper(); svc.onPrepareForEnd(mTarget); } + + + static void assertEmpty(Rect r) { + if (r != null && !r.isEmpty()) { + fail("Not true that " + r + " is empty"); + } + } + + static void assertContains(Rect parent, Rect child) { + if (!parent.contains(child)) { + fail("Not true that " + parent + " contains " + child); + } + } + + static void assertRectEquals(Rect parent, Rect child) { + if (!parent.equals(child)) { + fail("Not true that " + parent + " is equal to " + child); + } + } + + static Rect getVisibleRect(View v) { + Rect r = new Rect(0, 0, v.getWidth(), v.getHeight()); + v.getLocalVisibleRect(r); + return r; + } + + + static int assertScrollToY(View v, int scrollY) { + v.scrollTo(0, scrollY); + int dest = v.getScrollY(); + assertEquals(scrollY, dest); + return scrollY; + } + + static void assertRequestedRectCompletelyVisible(int startScrollY, Rect requestRect, + Rect localVisibleNow) { + Rect captured = new Rect(localVisibleNow); + captured.offset(0, -startScrollY); // make relative + + if (!captured.contains(requestRect)) { + fail("Not true that all of " + requestRect + " is contained by " + captured); + } + } + static void assertRequestedRectPartiallyVisible(int startScrollY, Rect requestRect, + Rect localVisibleNow) { + Rect captured = new Rect(localVisibleNow); + captured.offset(0, -startScrollY); // make relative + + if (!Rect.intersects(captured, requestRect)) { + fail("Not true that any of " + requestRect + " intersects " + captured); + } + } } diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index b63a19187b05..1cdc75aa1f40 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -23,8 +23,6 @@ import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; import static android.app.servertransaction.ActivityLifecycleItem.ON_START; import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP; -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; - import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -32,11 +30,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.after; -import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Activity; @@ -56,7 +50,6 @@ import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; -import android.testing.PollingCheck; import android.view.WindowManagerGlobal; import androidx.test.annotation.UiThreadTest; @@ -70,8 +63,6 @@ import org.mockito.Mockito; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; -import java.util.concurrent.TimeUnit; - /** * Test for verifying {@link android.app.ActivityThread} class. * @@ -85,7 +76,6 @@ import java.util.concurrent.TimeUnit; @MediumTest @Presubmit public class ActivityThreadClientTest { - private static final long WAIT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2); @Test @UiThreadTest @@ -162,63 +152,6 @@ public class ActivityThreadClientTest { } } - @Test - public void testLifecycleOfRelaunch() throws Exception { - try (ClientMockSession clientSession = new ClientMockSession()) { - ActivityThread activityThread = clientSession.mockThread(); - ActivityClientRecord r = clientSession.stubActivityRecord(); - final TestActivity[] activity = new TestActivity[1]; - - // Verify for ON_CREATE state. Activity should not be relaunched. - getInstrumentation().runOnMainSync(() -> { - activity[0] = (TestActivity) clientSession.launchActivity(r); - }); - recreateAndVerifyNoRelaunch(activityThread, activity[0]); - - // Verify for ON_START state. Activity should be relaunched. - getInstrumentation().runOnMainSync(() -> clientSession.startActivity(r)); - recreateAndVerifyRelaunched(activityThread, activity[0], r, ON_START); - - // Verify for ON_RESUME state. Activity should be relaunched. - getInstrumentation().runOnMainSync(() -> clientSession.resumeActivity(r)); - recreateAndVerifyRelaunched(activityThread, activity[0], r, ON_RESUME); - - // Verify for ON_PAUSE state. Activity should be relaunched. - getInstrumentation().runOnMainSync(() -> clientSession.pauseActivity(r)); - recreateAndVerifyRelaunched(activityThread, activity[0], r, ON_PAUSE); - - // Verify for ON_STOP state. Activity should be relaunched. - getInstrumentation().runOnMainSync(() -> clientSession.stopActivity(r)); - recreateAndVerifyRelaunched(activityThread, activity[0], r, ON_STOP); - - // Verify for ON_DESTROY state. Activity should not be relaunched. - getInstrumentation().runOnMainSync(() -> clientSession.destroyActivity(r)); - recreateAndVerifyNoRelaunch(activityThread, activity[0]); - } - } - - private void recreateAndVerifyNoRelaunch(ActivityThread activityThread, TestActivity activity) { - clearInvocations(activityThread); - getInstrumentation().runOnMainSync(() -> activity.recreate()); - - verify(activityThread, after(WAIT_TIMEOUT_MS).never()) - .handleRelaunchActivity(any(), any()); - } - - private void recreateAndVerifyRelaunched(ActivityThread activityThread, TestActivity activity, - ActivityClientRecord r, int expectedState) throws Exception { - clearInvocations(activityThread); - getInstrumentation().runOnMainSync(() -> activity.recreate()); - - verify(activityThread, timeout(WAIT_TIMEOUT_MS)).handleRelaunchActivity(any(), any()); - - // Wait for the relaunch to complete. - PollingCheck.check("Waiting for the expected state " + expectedState + " timeout", - WAIT_TIMEOUT_MS, - () -> expectedState == r.getLifecycleState()); - assertEquals(expectedState, r.getLifecycleState()); - } - private class ClientMockSession implements AutoCloseable { private MockitoSession mMockSession; private ActivityThread mThread; @@ -267,11 +200,6 @@ public class ActivityThreadClientTest { false /* getNonConfigInstance */, "test"); } - private ActivityThread mockThread() { - spyOn(mThread); - return mThread; - } - private ActivityClientRecord stubActivityRecord() { ComponentName component = new ComponentName( InstrumentationRegistry.getInstrumentation().getContext(), TestActivity.class); diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 1c0a526f536c..de2a7b2c15e3 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -807,7 +807,8 @@ public class AudioTrack extends PlayerBase int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes, sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat, mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/, - offload, encapsulationMode, tunerConfiguration); + offload, encapsulationMode, tunerConfiguration, + getCurrentOpPackageName()); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing AudioTrack."); return; // with mState == STATE_UNINITIALIZED @@ -893,7 +894,8 @@ public class AudioTrack extends PlayerBase nativeTrackInJavaObj, false /*offload*/, ENCAPSULATION_MODE_NONE, - null /* tunerConfiguration */); + null /* tunerConfiguration */, + "" /* opPackagename */); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing AudioTrack."); return; // with mState == STATE_UNINITIALIZED @@ -4062,7 +4064,8 @@ public class AudioTrack extends PlayerBase Object /*AudioAttributes*/ attributes, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int mode, int[] sessionId, long nativeAudioTrack, - boolean offload, int encapsulationMode, Object tunerConfiguration); + boolean offload, int encapsulationMode, Object tunerConfiguration, + @NonNull String opPackageName); private native final void native_finalize(); diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 49e416080041..36ae3ec75a99 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -672,7 +672,8 @@ public class MediaPlayer extends PlayerBase /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ - native_setup(new WeakReference<MediaPlayer>(this)); + native_setup(new WeakReference<MediaPlayer>(this), + getCurrentOpPackageName()); baseRegisterPlayer(); } @@ -2378,7 +2379,7 @@ public class MediaPlayer extends PlayerBase private native final int native_setMetadataFilter(Parcel request); private static native final void native_init(); - private native final void native_setup(Object mediaplayer_this); + private native void native_setup(Object mediaplayerThis, @NonNull String opPackageName); private native final void native_finalize(); /** diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java index ee8f1b3eec77..df5e85edbc30 100644 --- a/media/java/android/media/PlayerBase.java +++ b/media/java/android/media/PlayerBase.java @@ -27,6 +27,7 @@ import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.GuardedBy; @@ -622,4 +623,8 @@ public abstract class PlayerBase { Log.w(className, "See the documentation of " + opName + " for what to use instead with " + "android.media.AudioAttributes to qualify your playback use case"); } + + protected String getCurrentOpPackageName() { + return TextUtils.emptyIfNull(ActivityThread.currentOpPackageName()); + } } diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 55aac09b0f65..bd8d2e9f77a4 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -33,6 +33,7 @@ #include <utils/threads.h> #include "jni.h" #include <nativehelper/JNIPlatformHelp.h> +#include <nativehelper/ScopedUtfChars.h> #include "android_runtime/AndroidRuntime.h" #include "android_runtime/android_view_Surface.h" #include "android_runtime/Log.h" @@ -944,10 +945,12 @@ android_media_MediaPlayer_native_init(JNIEnv *env) } static void -android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) +android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, + jstring opPackageName) { ALOGV("native_setup"); - sp<MediaPlayer> mp = new MediaPlayer(); + ScopedUtfChars opPackageNameStr(env, opPackageName); + sp<MediaPlayer> mp = new MediaPlayer(opPackageNameStr.c_str()); if (mp == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; @@ -1403,7 +1406,7 @@ static const JNINativeMethod gMethods[] = { {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, - {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, + {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;)V",(void *)android_media_MediaPlayer_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, diff --git a/media/packages/BluetoothMidiService/Android.bp b/media/packages/BluetoothMidiService/Android.bp index 48fc329276bd..25c34c3631dc 100644 --- a/media/packages/BluetoothMidiService/Android.bp +++ b/media/packages/BluetoothMidiService/Android.bp @@ -29,6 +29,5 @@ android_app { "src/**/*.java", ], platform_apis: true, - certificate: "platform", manifest: "AndroidManifest.xml", } diff --git a/media/packages/BluetoothMidiService/AndroidManifest.xml b/media/packages/BluetoothMidiService/AndroidManifest.xml index b88bf2a0b2b7..fc96fd926e2d 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 ebe62b039434..bfb05469adb9 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/system-current.txt b/non-updatable-api/system-current.txt index d1264dfdd36d..7cce0f2f4b3e 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -219,6 +219,7 @@ package android { 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 90396717de9f..1a6fdfa9c996 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 @@ import dagger.Subcomponent; @Subcomponent(modules = { CarComponentBinder.class, DependencyProvider.class, - DependencyBinder.class, PipModule.class, SystemUIModule.class, CarSystemUIModule.class, diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index 3eea5132da1d..51fda965dcd0 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -52,10 +52,10 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.ShadeControllerImpl; import com.android.systemui.statusbar.policy.BatteryController; @@ -92,7 +92,7 @@ abstract class CarSystemUIModule { Context context, StatusBarStateController statusBarStateController, KeyguardBypassController bypassController, - NotificationGroupManager groupManager, + GroupMembershipManager groupManager, ConfigurationController configurationController) { return new HeadsUpManagerPhone(context, statusBarStateController, bypassController, groupManager, configurationController); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java index a2ba880facfe..fef032414bb9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java @@ -16,20 +16,19 @@ package com.android.systemui.car; +import android.annotation.NonNull; import android.app.ActivityManager; import android.car.settings.CarSettings; -import android.content.ContentResolver; -import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; -import android.provider.Settings; -import com.android.systemui.Dependency; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl; +import com.android.systemui.util.settings.GlobalSettings; +import com.android.systemui.util.settings.SecureSettings; import javax.inject.Inject; @@ -40,30 +39,33 @@ import javax.inject.Inject; @SysUISingleton public class CarDeviceProvisionedControllerImpl extends DeviceProvisionedControllerImpl implements CarDeviceProvisionedController { - private static final Uri USER_SETUP_IN_PROGRESS_URI = Settings.Secure.getUriFor( - CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS); - private final ContentObserver mCarSettingsObserver = new ContentObserver( - Dependency.get(Dependency.MAIN_HANDLER)) { - - @Override - public void onChange(boolean selfChange, Uri uri, int flags) { - if (USER_SETUP_IN_PROGRESS_URI.equals(uri)) { - notifyUserSetupInProgressChanged(); - } - } - }; - private final ContentResolver mContentResolver; + private final Uri mUserSetupInProgressUri; + private final ContentObserver mCarSettingsObserver; + private final Handler mMainHandler; + private final SecureSettings mSecureSettings; @Inject - public CarDeviceProvisionedControllerImpl(Context context, @Main Handler mainHandler, - BroadcastDispatcher broadcastDispatcher) { - super(context, mainHandler, broadcastDispatcher); - mContentResolver = context.getContentResolver(); + public CarDeviceProvisionedControllerImpl(@Main Handler mainHandler, + BroadcastDispatcher broadcastDispatcher, GlobalSettings globalSetting, + SecureSettings secureSettings) { + super(mainHandler, broadcastDispatcher, globalSetting, secureSettings); + mMainHandler = mainHandler; + mSecureSettings = secureSettings; + mUserSetupInProgressUri = mSecureSettings.getUriFor( + CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS); + mCarSettingsObserver = new ContentObserver(mMainHandler) { + @Override + public void onChange(boolean selfChange, Uri uri, int flags) { + if (mUserSetupInProgressUri.equals(uri)) { + notifyUserSetupInProgressChanged(); + } + } + }; } @Override public boolean isUserSetupInProgress(int user) { - return Settings.Secure.getIntForUser(mContentResolver, + return mSecureSettings.getIntForUser( CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS, /* def= */ 0, user) != 0; } @@ -73,7 +75,7 @@ public class CarDeviceProvisionedControllerImpl extends DeviceProvisionedControl } @Override - public void addCallback(DeviceProvisionedListener listener) { + public void addCallback(@NonNull DeviceProvisionedListener listener) { super.addCallback(listener); if (listener instanceof CarDeviceProvisionedListener) { ((CarDeviceProvisionedListener) listener).onUserSetupInProgressChanged(); @@ -82,9 +84,9 @@ public class CarDeviceProvisionedControllerImpl extends DeviceProvisionedControl @Override protected void startListening(int user) { - mContentResolver.registerContentObserver( - USER_SETUP_IN_PROGRESS_URI, /* notifyForDescendants= */ true, mCarSettingsObserver, - user); + mSecureSettings.registerContentObserverForUser( + mUserSetupInProgressUri, /* notifyForDescendants= */ true, + mCarSettingsObserver, user); // The SUW Flag observer is registered before super.startListening() so that the observer is // in place before DeviceProvisionedController starts to track user switches which avoids // an edge case where our observer gets registered twice. @@ -94,16 +96,16 @@ public class CarDeviceProvisionedControllerImpl extends DeviceProvisionedControl @Override protected void stopListening() { super.stopListening(); - mContentResolver.unregisterContentObserver(mCarSettingsObserver); + mSecureSettings.unregisterContentObserver(mCarSettingsObserver); } @Override public void onUserSwitched(int newUserId) { super.onUserSwitched(newUserId); - mContentResolver.unregisterContentObserver(mCarSettingsObserver); - mContentResolver.registerContentObserver( - USER_SETUP_IN_PROGRESS_URI, /* notifyForDescendants= */ true, mCarSettingsObserver, - newUserId); + mSecureSettings.unregisterContentObserver(mCarSettingsObserver); + mSecureSettings.registerContentObserverForUser( + mUserSetupInProgressUri, /* notifyForDescendants= */ true, + mCarSettingsObserver, newUserId); } private void notifyUserSetupInProgressChanged() { diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java index 276ddfbc2b4f..dadbc22760b9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java @@ -18,7 +18,6 @@ package com.android.systemui.car.keyguard; import android.car.Car; import android.car.user.CarUserManager; -import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.util.Log; @@ -28,20 +27,17 @@ import android.view.ViewRootImpl; import androidx.annotation.VisibleForTesting; -import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardViewController; import com.android.keyguard.ViewMediatorCallback; +import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.R; -import com.android.systemui.SystemUIFactory; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.car.navigationbar.CarNavigationBarController; import com.android.systemui.car.window.OverlayViewController; import com.android.systemui.car.window.OverlayViewGlobalStateController; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.keyguard.DismissCallbackRegistry; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.KeyguardBypassController; @@ -63,18 +59,14 @@ public class CarKeyguardViewController extends OverlayViewController implements private static final String TAG = "CarKeyguardViewController"; private static final boolean DEBUG = true; - private final Context mContext; private final Handler mHandler; private final CarServiceProvider mCarServiceProvider; private final KeyguardStateController mKeyguardStateController; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; - private final LockPatternUtils mLockPatternUtils; - private final FalsingManager mFalsingManager; - private final Lazy<KeyguardBypassController> mKeyguardBypassControllerLazy; - private final DismissCallbackRegistry mDismissCallbackRegistry; private final ViewMediatorCallback mViewMediatorCallback; private final CarNavigationBarController mCarNavigationBarController; + private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; // Needed to instantiate mBouncer. private final KeyguardBouncer.BouncerExpansionCallback mExpansionCallback = new KeyguardBouncer.BouncerExpansionCallback() { @@ -107,7 +99,6 @@ public class CarKeyguardViewController extends OverlayViewController implements @Inject public CarKeyguardViewController( - Context context, @Main Handler mainHandler, CarServiceProvider carServiceProvider, OverlayViewGlobalStateController overlayViewGlobalStateController, @@ -116,26 +107,18 @@ public class CarKeyguardViewController extends OverlayViewController implements Lazy<BiometricUnlockController> biometricUnlockControllerLazy, ViewMediatorCallback viewMediatorCallback, CarNavigationBarController carNavigationBarController, - /* The params below are only used to reuse KeyguardBouncer */ - LockPatternUtils lockPatternUtils, - DismissCallbackRegistry dismissCallbackRegistry, - FalsingManager falsingManager, - Lazy<KeyguardBypassController> keyguardBypassControllerLazy) { + KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) { super(R.id.keyguard_stub, overlayViewGlobalStateController); - mContext = context; mHandler = mainHandler; mCarServiceProvider = carServiceProvider; mKeyguardStateController = keyguardStateController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mBiometricUnlockControllerLazy = biometricUnlockControllerLazy; - mLockPatternUtils = lockPatternUtils; - mFalsingManager = falsingManager; - mKeyguardBypassControllerLazy = keyguardBypassControllerLazy; - mDismissCallbackRegistry = dismissCallbackRegistry; mViewMediatorCallback = viewMediatorCallback; mCarNavigationBarController = carNavigationBarController; + mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory; registerUserSwitchedListener(); } @@ -147,11 +130,9 @@ public class CarKeyguardViewController extends OverlayViewController implements @Override public void onFinishInflate() { - mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext, - mViewMediatorCallback, mLockPatternUtils, - getLayout().findViewById(R.id.keyguard_container), mDismissCallbackRegistry, - mExpansionCallback, mKeyguardStateController, mFalsingManager, - mKeyguardBypassControllerLazy.get()); + mBouncer = mKeyguardBouncerComponentFactory + .build(getLayout().findViewById(R.id.keyguard_container), mExpansionCallback) + .createKeyguardBouncer(); mBiometricUnlockControllerLazy.get().setKeyguardViewController(this); } @@ -359,9 +340,8 @@ public class CarKeyguardViewController extends OverlayViewController implements public void registerStatusBar(StatusBar statusBar, ViewGroup container, NotificationPanelViewController notificationPanelViewController, BiometricUnlockController biometricUnlockController, - DismissCallbackRegistry dismissCallbackRegistry, ViewGroup lockIconContainer, - View notificationContainer, KeyguardBypassController bypassController, - FalsingManager falsingManager) { + ViewGroup lockIconContainer, + View notificationContainer, KeyguardBypassController bypassController) { // no-op } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java index 38e1a48ab3a7..fe4cba8e73cd 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java @@ -91,7 +91,6 @@ public class NotificationPanelViewController extends OverlayPanelViewController private RecyclerView mNotificationList; private NotificationViewController mNotificationViewController; - private boolean mIsTracking; private boolean mNotificationListAtEnd; private float mFirstTouchDownOnGlassPane; private boolean mNotificationListAtEndAtTimeOfTouch; @@ -306,7 +305,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController mFirstTouchDownOnGlassPane = event.getRawX(); mNotificationListAtEndAtTimeOfTouch = mNotificationListAtEnd; // Reset the tracker when there is a touch down on the glass pane. - mIsTracking = false; + setIsTracking(false); // Pass the down event to gesture detector so that it knows where the touch event // started. closeGestureDetector.onTouchEvent(event); @@ -341,15 +340,15 @@ public class NotificationPanelViewController extends OverlayPanelViewController // If the card is swiping we should not allow the notification shade to close. // Hence setting mNotificationListAtEndAtTimeOfTouch to false will stop that - // for us. We are also checking for mIsTracking because while swiping the + // for us. We are also checking for isTracking() because while swiping the // notification shade to close if the user goes a bit horizontal while swiping // upwards then also this should close. - if (mIsNotificationCardSwiping && !mIsTracking) { + if (mIsNotificationCardSwiping && !isTracking()) { mNotificationListAtEndAtTimeOfTouch = false; } boolean handled = closeGestureDetector.onTouchEvent(event); - boolean isTracking = mIsTracking; + boolean isTracking = isTracking(); Rect rect = getLayout().getClipBounds(); float clippedHeight = 0; if (rect != null) { diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java index 5bd8797c5349..023b5b4f5f30 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java @@ -131,7 +131,7 @@ public class UserGridRecyclerView extends RecyclerView { } private List<UserInfo> getUsersForUserGrid() { - return mUserManager.getUsers(/* excludeDying= */ true) + return mUserManager.getAliveUsers() .stream() .filter(UserInfo::supportsSwitchToByUser) .collect(Collectors.toList()); @@ -338,7 +338,7 @@ public class UserGridRecyclerView extends RecyclerView { maxSupportedUsers -= 1; } - List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true); + List<UserInfo> users = mUserManager.getAliveUsers(); // Count all users that are managed profiles of another user. int managedProfilesCount = 0; diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java index bde31f18d8fd..1b00c6301011 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java @@ -297,14 +297,17 @@ public abstract class OverlayPanelViewController extends OverlayViewController { float from = getCurrentStartPosition(rect); if (from != to) { animate(from, to, velocity, isClosing); - return; } + + // If we swipe down the notification panel all the way to the bottom of the screen + // (i.e. from == to), then we have finished animating the panel. + return; } // We will only be here if the shade is being opened programmatically or via button when // height of the layout was not calculated. - ViewTreeObserver notificationTreeObserver = getLayout().getViewTreeObserver(); - notificationTreeObserver.addOnGlobalLayoutListener( + ViewTreeObserver panelTreeObserver = getLayout().getViewTreeObserver(); + panelTreeObserver.addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { @@ -507,6 +510,11 @@ public abstract class OverlayPanelViewController extends OverlayViewController { return mIsTracking; } + /** Sets whether the panel is currently tracking or not. */ + protected final void setIsTracking(boolean isTracking) { + mIsTracking = isTracking; + } + /** Returns {@code true} if the panel is currently animating. */ protected final boolean isAnimating() { return mIsAnimating; @@ -545,7 +553,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController { } setPanelVisible(true); - // clips the view for the notification shade when the user scrolls to open. + // clips the view for the panel when the user scrolls to open. setViewClipBounds((int) event2.getRawY()); // Initially the scroll starts with height being zero. This checks protects from divide @@ -600,11 +608,11 @@ public abstract class OverlayPanelViewController extends OverlayViewController { boolean isInClosingDirection = mAnimateDirection * distanceY > 0; // This check is to figure out if onScroll was called while swiping the card at - // bottom of the list. At that time we should not allow notification shade to + // bottom of the panel. At that time we should not allow panel to // close. We are also checking for the upwards swipe gesture here because it is - // possible if a user is closing the notification shade and while swiping starts + // possible if a user is closing the panel and while swiping starts // to open again but does not fling. At that time we should allow the - // notification shade to close fully or else it would stuck in between. + // panel to close fully or else it would stuck in between. if (Math.abs(getLayout().getHeight() - y) > SWIPE_DOWN_MIN_DISTANCE && isInClosingDirection) { setViewClipBounds((int) y); diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java index 62dc23624520..63d4004fb640 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.Context; import android.os.Handler; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -35,20 +34,17 @@ import android.view.ViewGroup; import androidx.test.filters.SmallTest; -import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; +import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.car.navigationbar.CarNavigationBarController; import com.android.systemui.car.window.OverlayViewGlobalStateController; -import com.android.systemui.keyguard.DismissCallbackRegistry; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.KeyguardBouncer; -import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; @@ -58,31 +54,36 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import dagger.Lazy; - @CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest public class CarKeyguardViewControllerTest extends SysuiTestCase { - private TestableCarKeyguardViewController mCarKeyguardViewController; + private CarKeyguardViewController mCarKeyguardViewController; @Mock private OverlayViewGlobalStateController mOverlayViewGlobalStateController; @Mock - private KeyguardBouncer mBouncer; + private CarKeyguardViewController.OnKeyguardCancelClickedListener mCancelClickedListener; @Mock - private CarNavigationBarController mCarNavigationBarController; + private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; @Mock - private CarKeyguardViewController.OnKeyguardCancelClickedListener mCancelClickedListener; + private KeyguardBouncerComponent mKeyguardBouncerComponent; + @Mock + private KeyguardBouncer mBouncer; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mCarKeyguardViewController = new TestableCarKeyguardViewController( - mContext, + when(mKeyguardBouncerComponentFactory.build( + any(ViewGroup.class), + any(KeyguardBouncer.BouncerExpansionCallback.class))) + .thenReturn(mKeyguardBouncerComponent); + when(mKeyguardBouncerComponent.createKeyguardBouncer()).thenReturn(mBouncer); + + mCarKeyguardViewController = new CarKeyguardViewController( Handler.getMain(), mock(CarServiceProvider.class), mOverlayViewGlobalStateController, @@ -91,10 +92,7 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { () -> mock(BiometricUnlockController.class), mock(ViewMediatorCallback.class), mock(CarNavigationBarController.class), - mock(LockPatternUtils.class), - mock(DismissCallbackRegistry.class), - mock(FalsingManager.class), - () -> mock(KeyguardBypassController.class) + mKeyguardBouncerComponentFactory ); mCarKeyguardViewController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate( R.layout.sysui_overlay_window, /* root= */ null)); @@ -202,33 +200,4 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { verify(mBouncer).hide(/* destroyView= */ true); } - - private class TestableCarKeyguardViewController extends CarKeyguardViewController { - - TestableCarKeyguardViewController(Context context, - Handler mainHandler, - CarServiceProvider carServiceProvider, - OverlayViewGlobalStateController overlayViewGlobalStateController, - KeyguardStateController keyguardStateController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - Lazy<BiometricUnlockController> biometricUnlockControllerLazy, - ViewMediatorCallback viewMediatorCallback, - CarNavigationBarController carNavigationBarController, - LockPatternUtils lockPatternUtils, - DismissCallbackRegistry dismissCallbackRegistry, - FalsingManager falsingManager, - Lazy<KeyguardBypassController> keyguardBypassControllerLazy) { - super(context, mainHandler, carServiceProvider, overlayViewGlobalStateController, - keyguardStateController, keyguardUpdateMonitor, biometricUnlockControllerLazy, - viewMediatorCallback, carNavigationBarController, lockPatternUtils, - dismissCallbackRegistry, falsingManager, keyguardBypassControllerLazy); - } - - @Override - public void onFinishInflate() { - super.onFinishInflate(); - setKeyguardBouncer(CarKeyguardViewControllerTest.this.mBouncer); - } - } - } diff --git a/packages/CompanionDeviceManager/TEST_MAPPING b/packages/CompanionDeviceManager/TEST_MAPPING new file mode 100644 index 000000000000..63f54fa35158 --- /dev/null +++ b/packages/CompanionDeviceManager/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "CtsOsTestCases", + "options": [ + { + "include-filter": "android.os.cts.CompanionDeviceManagerTest" + } + ] + } + ] +} 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 000000000000..16e91903084f --- /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 000000000000..4c338c968194 --- /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 000000000000..79037dbccf2d --- /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 000000000000..21ad128f81ff --- /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 000000000000..2ec5ba30cdc3 --- /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 a43412e116c8..b2808061586b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -49,11 +49,19 @@ public class Utils { 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 @@ public class Utils { * @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 a53bc9f966d2..bba69f29a290 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 androidx.preference.PreferenceViewHolder; 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 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt 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 class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt 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 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt } - 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 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt 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/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index bc58bfc97718..c57d4ad962bd 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -13,6 +13,7 @@ package com.android.settingslib.wifi; import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import android.content.Context; import android.content.Intent; @@ -250,6 +251,10 @@ public class WifiStatusTracker { statusLabel = mContext.getString(R.string.wifi_status_no_internet); } return; + } else if (!isDefaultNetwork && mDefaultNetworkCapabilities != null + && mDefaultNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { + statusLabel = mContext.getString(R.string.wifi_connected_low_quality); + return; } } 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 46e699d3bed5..40af7dc797b3 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 @@ package com.android.settingslib.wifi; 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 androidx.preference.PreferenceViewHolder; 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 @@ public class WifiEntryPreferenceTest { @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 @@ public class WifiEntryPreferenceTest { 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 @@ public class WifiEntryPreferenceTest { } @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/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 807fbed7d8fd..9c92b464dfbb 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -2576,7 +2576,7 @@ public class SettingsProvider extends ContentProvider { public void syncSsaidTableOnStart() { synchronized (mLock) { // Verify that each user's packages and ssaid's are in sync. - for (UserInfo user : mUserManager.getUsers(true)) { + for (UserInfo user : mUserManager.getAliveUsers()) { // Get all uids for the user's packages. final List<PackageInfo> packages; try { @@ -3007,7 +3007,7 @@ public class SettingsProvider extends ContentProvider { final long identity = Binder.clearCallingIdentity(); try { - List<UserInfo> users = mUserManager.getUsers(true); + List<UserInfo> users = mUserManager.getAliveUsers(); final int userCount = users.size(); for (int i = 0; i < userCount; i++) { @@ -3244,7 +3244,7 @@ public class SettingsProvider extends ContentProvider { // is a singleton generation entry for the global settings which // is already incremented be the caller. final Uri uri = getNotificationUriFor(key, name); - final List<UserInfo> users = mUserManager.getUsers(/*excludeDying*/ true); + final List<UserInfo> users = mUserManager.getAliveUsers(); for (int i = 0; i < users.size(); i++) { final int userId = users.get(i).id; if (mUserManager.isUserRunning(UserHandle.of(userId))) { @@ -3255,7 +3255,7 @@ public class SettingsProvider extends ContentProvider { } private void notifyLocationChangeForRunningUsers() { - final List<UserInfo> users = mUserManager.getUsers(/*excludeDying=*/ true); + final List<UserInfo> users = mUserManager.getAliveUsers(); for (int i = 0; i < users.size(); i++) { final int userId = users.get(i).id; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index b0483339d14e..05172279c4ed 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -796,16 +796,6 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe securityMode != SecurityMode.None && newView.needsInput()); } - private KeyguardSecurityViewFlipper getFlipper() { - for (int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - if (child instanceof KeyguardSecurityViewFlipper) { - return (KeyguardSecurityViewFlipper) child; - } - } - return null; - } - private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() { public void userActivity() { if (mSecurityCallback != null) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java index 6a90d00c1e75..9766ee128f7c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java @@ -21,9 +21,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewRootImpl; -import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardViewMediator; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; @@ -180,22 +178,18 @@ public interface KeyguardViewController { /** * Registers the StatusBar to which this Keyguard View is mounted. - * * @param statusBar * @param container * @param notificationPanelViewController * @param biometricUnlockController - * @param dismissCallbackRegistry * @param lockIconContainer * @param notificationContainer * @param bypassController - * @param falsingManager */ void registerStatusBar(StatusBar statusBar, ViewGroup container, NotificationPanelViewController notificationPanelViewController, BiometricUnlockController biometricUnlockController, - DismissCallbackRegistry dismissCallbackRegistry, ViewGroup lockIconContainer, View notificationContainer, - KeyguardBypassController bypassController, FalsingManager falsingManager); + KeyguardBypassController bypassController); } diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java b/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java new file mode 100644 index 000000000000..e65f19db5ac2 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java @@ -0,0 +1,30 @@ +/* + * 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.keyguard.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Qualifier; + +@Qualifier +@Documented +@Retention(RUNTIME) +public @interface ContainerView { +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java new file mode 100644 index 000000000000..84deaca096aa --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java @@ -0,0 +1,42 @@ +/* + * 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.keyguard.dagger; + +import android.view.ViewGroup; + +import com.android.systemui.statusbar.phone.KeyguardBouncer; + +import dagger.BindsInstance; +import dagger.Subcomponent; + +/** + * Dagger Subcomponent for the {@link KeyguardBouncer}. + */ +@Subcomponent +@KeyguardBouncerScope +public interface KeyguardBouncerComponent { + /** Simple factory for {@link KeyguardBouncerComponent}. */ + @Subcomponent.Factory + interface Factory { + KeyguardBouncerComponent build( + @BindsInstance @ContainerView ViewGroup container, + @BindsInstance KeyguardBouncer.BouncerExpansionCallback bouncerExpansionCallback); + } + + /** */ + KeyguardBouncer createKeyguardBouncer(); +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java new file mode 100644 index 000000000000..207ac2852f2f --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java @@ -0,0 +1,32 @@ +/* + * 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.keyguard.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +/** + * Scope annotation for singleton items within the StatusBarComponent. + */ +@Documented +@Retention(RUNTIME) +@Scope +public @interface KeyguardBouncerScope {} diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 27809b50d746..ed78c94d45f9 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -77,6 +77,7 @@ import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment; import com.android.systemui.statusbar.notification.NotificationFilter; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; @@ -88,7 +89,6 @@ import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.LockscreenGestureLogger; import com.android.systemui.statusbar.phone.ManagedProfileController; import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -276,7 +276,7 @@ public class Dependency { @Inject Lazy<StatusBarStateController> mStatusBarStateController; @Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager; @Inject Lazy<NotificationGroupAlertTransferHelper> mNotificationGroupAlertTransferHelper; - @Inject Lazy<NotificationGroupManager> mNotificationGroupManager; + @Inject Lazy<NotificationGroupManagerLegacy> mNotificationGroupManager; @Inject Lazy<VisualStabilityManager> mVisualStabilityManager; @Inject Lazy<NotificationGutsManager> mNotificationGutsManager; @Inject Lazy<NotificationMediaManager> mNotificationMediaManager; @@ -468,7 +468,7 @@ public class Dependency { mProviders.put(NotificationLockscreenUserManager.class, mNotificationLockscreenUserManager::get); mProviders.put(VisualStabilityManager.class, mVisualStabilityManager::get); - mProviders.put(NotificationGroupManager.class, mNotificationGroupManager::get); + mProviders.put(NotificationGroupManagerLegacy.class, mNotificationGroupManager::get); mProviders.put(NotificationGroupAlertTransferHelper.class, mNotificationGroupAlertTransferHelper::get); mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index f5c364947a2f..f15949977754 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -19,25 +19,16 @@ package com.android.systemui; import android.content.Context; import android.content.res.Resources; import android.os.Handler; -import android.os.Looper; import android.util.Log; -import android.view.ViewGroup; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.widget.LockPatternUtils; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.dagger.DaggerGlobalRootComponent; import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.SysUIComponent; import com.android.systemui.dagger.WMComponent; -import com.android.systemui.keyguard.DismissCallbackRegistry; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider; -import com.android.systemui.statusbar.phone.KeyguardBouncer; -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 +74,16 @@ public class SystemUIFactory { 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 +97,15 @@ public class SystemUIFactory { .build(); } + public GlobalRootComponent getRootComponent() { return mRootComponent; } + public WMComponent getWMComponent() { + return mWMComponent; + } + public SysUIComponent getSysUIComponent() { return mSysUIComponent; } @@ -129,17 +130,4 @@ public class SystemUIFactory { Handler uiHandler) { return new ScreenshotNotificationSmartActionsProvider(); } - - public KeyguardBouncer createKeyguardBouncer(Context context, ViewMediatorCallback callback, - LockPatternUtils lockPatternUtils, ViewGroup container, - DismissCallbackRegistry dismissCallbackRegistry, - KeyguardBouncer.BouncerExpansionCallback expansionCallback, - KeyguardStateController keyguardStateController, FalsingManager falsingManager, - KeyguardBypassController bypassController) { - return new KeyguardBouncer(context, callback, lockPatternUtils, container, - dismissCallbackRegistry, falsingManager, - expansionCallback, keyguardStateController, - Dependency.get(KeyguardUpdateMonitor.class), bypassController, - new Handler(Looper.getMainLooper())); - } } diff --git a/packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.java b/packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.java new file mode 100644 index 000000000000..d4cc3f37b8dd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/appops/dagger/AppOpsModule.java @@ -0,0 +1,32 @@ +/* + * 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.appops.dagger; + +import com.android.systemui.appops.AppOpsController; +import com.android.systemui.appops.AppOpsControllerImpl; + +import dagger.Binds; +import dagger.Module; + +/** Dagger Module for code in the appops package. */ +@Module +public interface AppOpsModule { + /** */ + @Binds + AppOpsController provideAppOpsController(AppOpsControllerImpl controllerImpl); + +} diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 9e9d85a7cd1c..c81b7cefbbd7 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -104,11 +104,11 @@ import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.coordinator.BubbleCoordinator; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; @@ -164,7 +164,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi private final BubbleTaskStackListener mTaskStackListener; private BubbleExpandListener mExpandListener; @Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer; - private final NotificationGroupManager mNotificationGroupManager; + private final NotificationGroupManagerLegacy mNotificationGroupManager; private final ShadeController mShadeController; private final FloatingContentCoordinator mFloatingContentCoordinator; private final BubbleDataRepository mDataRepository; @@ -355,7 +355,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, - NotificationGroupManager groupManager, + NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager, NotifPipeline notifPipeline, FeatureFlags featureFlags, @@ -588,11 +588,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } }); - mNotificationGroupManager.addOnGroupChangeListener( - new NotificationGroupManager.OnGroupChangeListener() { + mNotificationGroupManager.registerGroupChangeListener( + new NotificationGroupManagerLegacy.OnGroupChangeListener() { @Override public void onGroupSuppressionChanged( - NotificationGroupManager.NotificationGroup group, + NotificationGroupManagerLegacy.NotificationGroup group, boolean suppressed) { // More notifications could be added causing summary to no longer // be suppressed -- in this case need to remove the key. @@ -650,8 +650,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // 3. User removes all bubbles // 4. We expect all the removed bubbles AND the summary (note: the summary was // never added to the suppressedSummary list in BubbleData, so we add this check) - NotificationEntry summary = - mNotificationGroupManager.getLogicalGroupSummary(entry.getSbn()); + NotificationEntry summary = mNotificationGroupManager.getLogicalGroupSummary(entry); if (summary != null) { ArrayList<NotificationEntry> summaryChildren = mNotificationGroupManager.getLogicalChildren(summary.getSbn()); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java index eecc41c697b3..9efc3c20f55a 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java @@ -34,8 +34,8 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ZenModeController; @@ -62,7 +62,7 @@ public interface BubbleModule { NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, - NotificationGroupManager groupManager, + NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager, NotifPipeline notifPipeline, FeatureFlags featureFlags, 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 e2a6d6c51d4d..000000000000 --- 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 fd4a4093110f..c5dc8cccfdf4 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 @@ import dagger.Module; * * 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 36fd3373290d..00fdf55b28e0 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 @@ package com.android.systemui.dagger; import android.content.Context; +import com.android.systemui.util.concurrency.ThreadFactory; + import javax.inject.Singleton; import dagger.BindsInstance; @@ -53,4 +55,9 @@ public interface GlobalRootComponent { * 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 000000000000..406981d0c4ad --- /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 e4e3d7aacdf0..2622593880ba 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.pip.phone.dagger.PipModule; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.InjectionInflationController; +import dagger.BindsInstance; import dagger.Subcomponent; /** @@ -35,7 +36,6 @@ import dagger.Subcomponent; @Subcomponent(modules = { DefaultComponentBinder.class, DependencyProvider.class, - DependencyBinder.class, PipModule.class, SystemUIBinder.class, SystemUIModule.class, @@ -47,6 +47,9 @@ public interface SysUIComponent { */ @Subcomponent.Builder interface Builder { + @BindsInstance + Builder setStubAPIClass(WMComponent.StubAPIClass stubAPIClass); + SysUIComponent build(); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java index a021114c138b..2c0b04fed810 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java @@ -46,11 +46,11 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.phone.DozeServiceHost; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowControllerImpl; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.ShadeControllerImpl; @@ -143,7 +143,7 @@ public abstract class SystemUIDefaultModule { Context context, StatusBarStateController statusBarStateController, KeyguardBypassController bypassController, - NotificationGroupManager groupManager, + GroupMembershipManager groupManager, ConfigurationController configurationController) { return new HeadsUpManagerPhone(context, statusBarStateController, bypassController, groupManager, configurationController); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index e985e3d7ef90..8f4e738e5a5f 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -16,14 +16,18 @@ package com.android.systemui.dagger; +import com.android.keyguard.dagger.KeyguardBouncerComponent; 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 +41,15 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfC 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,20 +61,29 @@ import dagger.Provides; * 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, DozeComponent.class, ExpandableNotificationRowComponent.class, + KeyguardBouncerComponent.class, NotificationShelfComponent.class, FragmentService.FragmentCreator.class}) public abstract class SystemUIModule { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java index 929b61a3421c..ad90eff3c969 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 @@ public interface WMComponent { 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/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index 342818de3d1e..d9f971731f29 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -30,6 +30,8 @@ import android.os.UserHandle; import android.provider.Settings; import android.view.Display; +import androidx.annotation.Nullable; + import com.android.systemui.doze.dagger.BrightnessSensor; import com.android.systemui.doze.dagger.DozeScope; import com.android.systemui.doze.dagger.WrappedService; @@ -75,7 +77,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi @Inject public DozeScreenBrightness(Context context, @WrappedService DozeMachine.Service service, - AsyncSensorManager sensorManager, @BrightnessSensor Sensor lightSensor, + AsyncSensorManager sensorManager, @Nullable @BrightnessSensor Sensor lightSensor, DozeHost host, Handler handler, AlwaysOnDisplayPolicy alwaysOnDisplayPolicy) { mContext = context; mDozeService = service; diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java index 04f7c368fdc4..b89946028aeb 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java +++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java @@ -20,6 +20,8 @@ import android.content.Context; import android.hardware.Sensor; import android.os.Handler; +import androidx.annotation.Nullable; + import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeAuthRemover; @@ -91,6 +93,7 @@ public abstract class DozeModule { @Provides @BrightnessSensor + @Nullable static Sensor providesBrightnessSensor(AsyncSensorManager sensorManager, Context context) { return DozeSensors.findSensorWithType(sensorManager, context.getString(R.string.doze_brightness_sensor_type)); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 33407918f938..2705f07069bf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -2184,8 +2184,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { BiometricUnlockController biometricUnlockController, ViewGroup lockIconContainer, View notificationContainer, KeyguardBypassController bypassController) { mKeyguardViewControllerLazy.get().registerStatusBar(statusBar, container, panelView, - biometricUnlockController, mDismissCallbackRegistry, lockIconContainer, - notificationContainer, bypassController, mFalsingManager); + biometricUnlockController, lockIconContainer, + notificationContainer, bypassController); return mKeyguardViewControllerLazy.get(); } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index a003d8365810..e5a9ac10389f 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 @@ class MediaCarouselController @Inject constructor( // 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 aec3543de4eb..c7e78174f474 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 @@ public class NavigationBar implements View.OnAttachStateChangeListener, 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 0354c727c92c..8ef9b092bc00 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 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du 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/power/dagger/PowerModule.java b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java new file mode 100644 index 000000000000..8b8941a9112d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java @@ -0,0 +1,32 @@ +/* + * 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.power.dagger; + +import com.android.systemui.power.PowerNotificationWarnings; +import com.android.systemui.power.PowerUI; + +import dagger.Binds; +import dagger.Module; + + +/** 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 8740581240b5..8ff96c8a4a37 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 android.os.Handler; 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.CastController; 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 @@ public interface QSModule { manager.init(); return manager; } + + + /** */ + @Binds + QSHost provideQsHost(QSTileHost controllerImpl); } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index e24fbc6cca9d..7dd4edd233bd 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 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset 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 6b42f2e07bc3..74e0229c4992 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 @@ public enum ScreenshotEvent implements UiEventLogger.UiEventEnum { @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/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index 852c05547e32..38c7e5c50f63 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -36,12 +36,12 @@ import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.inflation.LowPriorityInflationHelper; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.util.Assert; import java.util.ArrayList; @@ -72,7 +72,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle // Dependencies: private final DynamicChildBindController mDynamicChildBindController; protected final NotificationLockscreenUserManager mLockscreenUserManager; - protected final NotificationGroupManager mGroupManager; + protected final NotificationGroupManagerLegacy mGroupManager; protected final VisualStabilityManager mVisualStabilityManager; private final SysuiStatusBarStateController mStatusBarStateController; private final NotificationEntryManager mEntryManager; @@ -107,7 +107,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle Context context, @Main Handler mainHandler, NotificationLockscreenUserManager notificationLockscreenUserManager, - NotificationGroupManager groupManager, + NotificationGroupManagerLegacy groupManager, VisualStabilityManager visualStabilityManager, StatusBarStateController statusBarStateController, NotificationEntryManager notificationEntryManager, @@ -187,13 +187,13 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle ent.setSensitive(sensitive, deviceSensitive); ent.getRow().setNeedsRedaction(needsRedaction); mLowPriorityInflationHelper.recheckLowPriorityViewAndInflate(ent, ent.getRow()); - boolean isChildInGroup = mGroupManager.isChildInGroupWithSummary(ent.getSbn()); + boolean isChildInGroup = mGroupManager.isChildInGroup(ent); boolean groupChangesAllowed = mVisualStabilityManager.areGroupChangesAllowed() // user isn't looking at notifs || !ent.hasFinishedInitialization(); // notif recently added - NotificationEntry parent = mGroupManager.getGroupSummary(ent.getSbn()); + NotificationEntry parent = mGroupManager.getGroupSummary(ent); if (!groupChangesAllowed) { // We don't to change groups while the user is looking at them boolean wasChildInGroup = ent.isChildInGroup(); @@ -431,8 +431,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle while(!stack.isEmpty()) { ExpandableNotificationRow row = stack.pop(); NotificationEntry entry = row.getEntry(); - boolean isChildNotification = - mGroupManager.isChildInGroupWithSummary(entry.getSbn()); + boolean isChildNotification = mGroupManager.isChildInGroup(entry); if (!onKeyguard) { // If mAlwaysExpandNonGroupedNotification is false, then only expand the @@ -448,9 +447,8 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry); if (!showOnKeyguard) { // min priority notifications should show if their summary is showing - if (mGroupManager.isChildInGroupWithSummary(entry.getSbn())) { - NotificationEntry summary = mGroupManager.getLogicalGroupSummary( - entry.getSbn()); + if (mGroupManager.isChildInGroup(entry)) { + NotificationEntry summary = mGroupManager.getLogicalGroupSummary(entry); if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(summary)) { showOnKeyguard = 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 44550b72e521..d15b8476b3c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java @@ -37,21 +37,29 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; 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; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.inflation.LowPriorityInflationHelper; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; 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.NotificationGroupManager; +import com.android.systemui.statusbar.phone.ManagedProfileController; +import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl; 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 @@ public interface StatusBarDependenciesModule { return new SmartReplyController(entryManager, statusBarService, clickNotifier); } + + /** */ + @Binds + NotificationRemoteInputManager.Callback provideNotificationRemoteInputManagerCallback( + StatusBarRemoteInputCallback callbackImpl); + /** */ @SysUISingleton @Provides @@ -143,7 +157,7 @@ public interface StatusBarDependenciesModule { Context context, @Main Handler mainHandler, NotificationLockscreenUserManager notificationLockscreenUserManager, - NotificationGroupManager groupManager, + NotificationGroupManagerLegacy groupManager, VisualStabilityManager visualStabilityManager, StatusBarStateController statusBarStateController, NotificationEntryManager notificationEntryManager, @@ -179,4 +193,22 @@ public interface StatusBarDependenciesModule { 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/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt index c68625c9d9ee..433c8b0d361d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt @@ -30,7 +30,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationContentView import com.android.systemui.statusbar.notification.stack.StackStateAnimator -import com.android.systemui.statusbar.phone.NotificationGroupManager +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy import java.util.concurrent.ConcurrentHashMap import javax.inject.Inject @@ -64,7 +64,7 @@ class ConversationNotificationProcessor @Inject constructor( @SysUISingleton class ConversationNotificationManager @Inject constructor( private val notificationEntryManager: NotificationEntryManager, - private val notificationGroupManager: NotificationGroupManager, + private val notificationGroupManager: NotificationGroupManagerLegacy, private val context: Context, @Main private val mainHandler: Handler ) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index b5f1c7ff9b62..e1e77b0723a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -48,13 +48,13 @@ import com.android.systemui.statusbar.NotificationUiAdjustment; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.util.Assert; import com.android.systemui.util.leak.LeakDetector; @@ -139,7 +139,7 @@ public class NotificationEntryManager implements private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>(); private final KeyguardEnvironment mKeyguardEnvironment; - private final NotificationGroupManager mGroupManager; + private final NotificationGroupManagerLegacy mGroupManager; private final NotificationRankingManager mRankingManager; private final FeatureFlags mFeatureFlags; private final ForegroundServiceDismissalFeatureController mFgsFeatureController; @@ -199,7 +199,7 @@ public class NotificationEntryManager implements */ public NotificationEntryManager( NotificationEntryManagerLogger logger, - NotificationGroupManager groupManager, + NotificationGroupManagerLegacy groupManager, NotificationRankingManager rankingManager, KeyguardEnvironment keyguardEnvironment, FeatureFlags featureFlags, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java index 590ccf830a78..73c7fd1b64a3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java @@ -34,7 +34,6 @@ import com.android.systemui.media.MediaFeatureFlag; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; import javax.inject.Inject; @@ -46,8 +45,6 @@ import javax.inject.Inject; @SysUISingleton public class NotificationFilter { - private final NotificationGroupManager mGroupManager = Dependency.get( - NotificationGroupManager.class); private final StatusBarStateController mStatusBarStateController; private final Boolean mIsMediaFlagEnabled; 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 8ce9d944b865..789e78e33671 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 @@ -60,6 +60,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.ContrastColorUtil; import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor; @@ -69,7 +70,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; import com.android.systemui.statusbar.notification.row.NotificationGuts; import com.android.systemui.statusbar.notification.stack.PriorityBucket; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import java.util.ArrayList; import java.util.List; @@ -430,7 +430,7 @@ public final class NotificationEntry extends ListEntry { * Get the children that are actually attached to this notification's row. * * TODO: Seems like most callers here should probably be using - * {@link NotificationGroupManager#getChildren} + * {@link NotificationGroupManagerLegacy#getChildren} */ public @Nullable List<NotificationEntry> getAttachedNotifChildren() { if (row == null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt index bab2686c5c9c..fb42c424f603 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt @@ -33,7 +33,7 @@ import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVI import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT import com.android.systemui.statusbar.notification.stack.PriorityBucket -import com.android.systemui.statusbar.phone.NotificationGroupManager +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy import com.android.systemui.statusbar.policy.HeadsUpManager import dagger.Lazy import java.util.Objects @@ -52,7 +52,7 @@ private const val TAG = "NotifRankingManager" */ open class NotificationRankingManager @Inject constructor( private val mediaManagerLazy: Lazy<NotificationMediaManager>, - private val groupManager: NotificationGroupManager, + private val groupManager: NotificationGroupManagerLegacy, private val headsUpManager: HeadsUpManager, private val notifFilter: NotificationFilter, private val logger: NotificationEntryManagerLogger, @@ -191,7 +191,7 @@ open class NotificationRankingManager @Inject constructor( private fun NotificationEntry.isConversation() = getPeopleNotificationType() != TYPE_NON_PERSON private fun NotificationEntry.getPeopleNotificationType() = - peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking) + peopleNotificationIdentifier.getPeopleNotificationType(this) private fun NotificationEntry.isHighPriority() = highPriorityProvider.isHighPriority(this) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt index dea11626a3f8..3aaa9acdb897 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt @@ -53,8 +53,7 @@ class ConversationCoordinator @Inject constructor( } private fun isConversation(entry: NotificationEntry): Boolean = - peopleNotificationIdentifier.getPeopleNotificationType(entry.sbn, entry.ranking) != - TYPE_NON_PERSON + peopleNotificationIdentifier.getPeopleNotificationType(entry) != TYPE_NON_PERSON companion object { private const val TAG = "ConversationCoordinator" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java index 6089aa26fe71..aec26474cf7d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java @@ -20,10 +20,10 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.RowContentBindParams; import com.android.systemui.statusbar.notification.row.RowContentBindStage; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import javax.inject.Inject; @@ -34,13 +34,13 @@ import javax.inject.Inject; @SysUISingleton public class LowPriorityInflationHelper { private final FeatureFlags mFeatureFlags; - private final NotificationGroupManager mGroupManager; + private final NotificationGroupManagerLegacy mGroupManager; private final RowContentBindStage mRowContentBindStage; @Inject LowPriorityInflationHelper( FeatureFlags featureFlags, - NotificationGroupManager groupManager, + NotificationGroupManagerLegacy groupManager, RowContentBindStage rowContentBindStage) { mFeatureFlags = featureFlags; mGroupManager = groupManager; @@ -78,7 +78,7 @@ public class LowPriorityInflationHelper { if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { isGroupChild = (entry.getParent() != GroupEntry.ROOT_ENTRY); } else { - isGroupChild = mGroupManager.isChildInGroupWithSummary(entry.getSbn()); + isGroupChild = mGroupManager.isChildInGroup(entry); } return entry.isAmbient() && !isGroupChild; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java index c44c59c02810..21d54c85160b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.statusbar.notification.collection.legacy; import android.annotation.Nullable; import android.service.notification.StatusBarNotification; @@ -22,14 +22,17 @@ import android.util.ArraySet; import android.util.Log; import com.android.systemui.Dependency; +import com.android.systemui.Dumpable; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; @@ -37,6 +40,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -46,13 +50,19 @@ import dagger.Lazy; /** * A class to handle notifications and their corresponding groups. + * This includes: + * 1. Determining whether an entry is a member of a group and whether it is a summary or a child + * 2. Tracking group expansion states */ @SysUISingleton -public class NotificationGroupManager implements OnHeadsUpChangedListener, StateListener { +public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener, StateListener, + GroupMembershipManager, GroupExpansionManager, Dumpable { private static final String TAG = "NotificationGroupManager"; private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>(); - private final ArraySet<OnGroupChangeListener> mListeners = new ArraySet<>(); + private final ArraySet<OnGroupExpansionChangeListener> mExpansionChangeListeners = + new ArraySet<>(); + private final ArraySet<OnGroupChangeListener> mGroupChangeListeners = new ArraySet<>(); private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier; private int mBarState = -1; private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>(); @@ -61,7 +71,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State @Nullable private BubbleController mBubbleController = null; @Inject - public NotificationGroupManager( + public NotificationGroupManagerLegacy( StatusBarStateController statusBarStateController, Lazy<PeopleNotificationIdentifier> peopleNotificationIdentifier) { statusBarStateController.addCallback(this); @@ -77,15 +87,19 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State /** * Add a listener for changes to groups. - * - * @param listener listener to add */ - public void addOnGroupChangeListener(OnGroupChangeListener listener) { - mListeners.add(listener); + public void registerGroupChangeListener(OnGroupChangeListener listener) { + mGroupChangeListeners.add(listener); } - public boolean isGroupExpanded(StatusBarNotification sbn) { - NotificationGroup group = mGroupMap.get(getGroupKey(sbn)); + @Override + public void registerGroupExpansionChangeListener(OnGroupExpansionChangeListener listener) { + mExpansionChangeListeners.add(listener); + } + + @Override + public boolean isGroupExpanded(NotificationEntry entry) { + NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn())); if (group == null) { return false; } @@ -103,8 +117,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State return group.expanded; } - public void setGroupExpanded(StatusBarNotification sbn, boolean expanded) { - NotificationGroup group = mGroupMap.get(getGroupKey(sbn)); + @Override + public void setGroupExpanded(NotificationEntry entry, boolean expanded) { + NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn())); if (group == null) { return; } @@ -114,12 +129,15 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State private void setGroupExpanded(NotificationGroup group, boolean expanded) { group.expanded = expanded; if (group.summary != null) { - for (OnGroupChangeListener listener : mListeners) { - listener.onGroupExpansionChanged(group.summary.getRow(), expanded); + for (OnGroupExpansionChangeListener listener : mExpansionChangeListeners) { + listener.onGroupExpansionChange(group.summary.getRow(), expanded); } } } + /** + * When we want to remove an entry from being tracked for grouping + */ public void onEntryRemoved(NotificationEntry removed) { onEntryRemovedInternal(removed, removed.getSbn()); mIsolatedEntries.remove(removed.getKey()); @@ -158,7 +176,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State if (group.children.isEmpty()) { if (group.summary == null) { mGroupMap.remove(groupKey); - for (OnGroupChangeListener listener : mListeners) { + for (OnGroupChangeListener listener : mGroupChangeListeners) { listener.onGroupRemoved(group, groupKey); } } @@ -184,7 +202,8 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State if (group == null) { group = new NotificationGroup(); mGroupMap.put(groupKey, group); - for (OnGroupChangeListener listener : mListeners) { + + for (OnGroupChangeListener listener : mGroupChangeListeners) { listener.onGroupCreated(group, groupKey); } } @@ -195,9 +214,8 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State Log.wtf(TAG, "Inconsistent entries found with the same key " + added.getKey() + "existing removed: " + existing.isRowRemoved() + (existingThrowable != null - ? Log.getStackTraceString(existingThrowable) + "\n": "") - + " added removed" + added.isRowRemoved() - , new Throwable()); + ? Log.getStackTraceString(existingThrowable) + "\n" : "") + + " added removed" + added.isRowRemoved(), new Throwable()); } group.children.put(added.getKey(), added); updateSuppression(group); @@ -206,12 +224,12 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State group.expanded = added.areChildrenExpanded(); updateSuppression(group); if (!group.children.isEmpty()) { - ArrayList<NotificationEntry> childrenCopy - = new ArrayList<>(group.children.values()); + ArrayList<NotificationEntry> childrenCopy = + new ArrayList<>(group.children.values()); for (NotificationEntry child : childrenCopy) { onEntryBecomingChild(child); } - for (OnGroupChangeListener listener : mListeners) { + for (OnGroupChangeListener listener : mGroupChangeListeners) { listener.onGroupCreatedFromChildren(group); } } @@ -243,7 +261,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State && group.summary.getSbn().getNotification().isGroupSummary() && (hasIsolatedChildren(group) || hasBubbles))); if (prevSuppressed != group.suppressed) { - for (OnGroupChangeListener listener : mListeners) { + for (OnGroupChangeListener listener : mGroupChangeListeners) { if (!mIsUpdatingUnchangedGroup) { listener.onGroupSuppressionChanged(group, group.suppressed); listener.onGroupsChanged(); @@ -306,6 +324,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State } } + /** + * Whether the given notification is the summary of a group that is being suppressed + */ public boolean isSummaryOfSuppressedGroup(StatusBarNotification sbn) { return isGroupSuppressed(getGroupKey(sbn)) && sbn.getNotification().isGroupSummary(); } @@ -315,13 +336,14 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State && getTotalNumberOfChildren(sbn) == 1; } - public boolean isOnlyChildInGroup(StatusBarNotification sbn) { + @Override + public boolean isOnlyChildInGroup(NotificationEntry entry) { + final StatusBarNotification sbn = entry.getSbn(); if (!isOnlyChild(sbn)) { return false; } - NotificationEntry logicalGroupSummary = getLogicalGroupSummary(sbn); - return logicalGroupSummary != null - && !logicalGroupSummary.getSbn().equals(sbn); + NotificationEntry logicalGroupSummary = getLogicalGroupSummary(entry); + return logicalGroupSummary != null && !logicalGroupSummary.getSbn().equals(sbn); } private int getTotalNumberOfChildren(StatusBarNotification sbn) { @@ -339,11 +361,12 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State private void setStatusBarState(int newState) { mBarState = newState; if (mBarState == StatusBarState.KEYGUARD) { - collapseAllGroups(); + collapseGroups(); } } - public void collapseAllGroups() { + @Override + public void collapseGroups() { // Because notifications can become isolated when the group becomes suppressed it can // lead to concurrent modifications while looping. We need to make a copy. ArrayList<NotificationGroup> groupCopy = new ArrayList<>(mGroupMap.values()); @@ -357,10 +380,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State } } - /** - * @return whether a given notification is a child in a group which has a summary - */ - public boolean isChildInGroupWithSummary(StatusBarNotification sbn) { + @Override + public boolean isChildInGroup(NotificationEntry entry) { + final StatusBarNotification sbn = entry.getSbn(); if (!isGroupChild(sbn)) { return false; } @@ -377,10 +399,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State return true; } - /** - * @return whether a given notification is a summary in a group which has children - */ - public boolean isSummaryOfGroup(StatusBarNotification sbn) { + @Override + public boolean isGroupSummary(NotificationEntry entry) { + final StatusBarNotification sbn = entry.getSbn(); if (!isGroupSummary(sbn)) { return false; } @@ -391,21 +412,14 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State return !group.children.isEmpty() && Objects.equals(group.summary.getSbn(), sbn); } - /** - * Get the summary of a specified status bar notification. For isolated notification this return - * itself. - */ - public NotificationEntry getGroupSummary(StatusBarNotification sbn) { - return getGroupSummary(getGroupKey(sbn)); + @Override + public NotificationEntry getGroupSummary(NotificationEntry entry) { + return getGroupSummary(getGroupKey(entry.getSbn())); } - /** - * Similar to {@link #getGroupSummary(StatusBarNotification)} but doesn't get the visual summary - * but the logical summary, i.e when a child is isolated, it still returns the summary as if - * it wasn't isolated. - */ - public NotificationEntry getLogicalGroupSummary(StatusBarNotification sbn) { - return getGroupSummary(sbn.getGroupKey()); + @Override + public NotificationEntry getLogicalGroupSummary(NotificationEntry entry) { + return getGroupSummary(entry.getSbn().getGroupKey()); } @Nullable @@ -436,14 +450,10 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State return children; } - /** - * Get the children that are in the summary's group, not including those isolated. - * - * @param summary summary of a group - * @return list of the children - */ - public @Nullable ArrayList<NotificationEntry> getChildren(StatusBarNotification summary) { - NotificationGroup group = mGroupMap.get(summary.getGroupKey()); + @Override + public @Nullable List<NotificationEntry> getChildren(ListEntry listEntrySummary) { + NotificationEntry summary = listEntrySummary.getRepresentativeEntry(); + NotificationGroup group = mGroupMap.get(summary.getSbn().getGroupKey()); if (group == null) { return null; } @@ -479,9 +489,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State return groupKey; } - /** @return group expansion state after toggling. */ - public boolean toggleGroupExpansion(StatusBarNotification sbn) { - NotificationGroup group = mGroupMap.get(getGroupKey(sbn)); + @Override + public boolean toggleGroupExpansion(NotificationEntry entry) { + NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn())); if (group == null) { return false; } @@ -494,10 +504,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State } /** - * Whether a notification is visually a group summary. - * - * @param sbn notification to check - * @return true if it is visually a group summary + * Is this notification the summary of a group? */ public boolean isGroupSummary(StatusBarNotification sbn) { if (isIsolated(sbn.getKey())) { @@ -536,14 +543,13 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State * @param entry the notification to check * @return true if the entry should be isolated */ - private boolean shouldIsolate(NotificationEntry entry) { StatusBarNotification sbn = entry.getSbn(); if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) { return false; } - int peopleNotificationType = mPeopleNotificationIdentifier.get().getPeopleNotificationType( - entry.getSbn(), entry.getRanking()); + int peopleNotificationType = + mPeopleNotificationIdentifier.get().getPeopleNotificationType(entry); if (peopleNotificationType == PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON) { return true; } @@ -576,7 +582,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State // When the notification gets added afterwards it is already isolated and therefore // it doesn't lead to an update. updateSuppression(mGroupMap.get(entry.getSbn().getGroupKey())); - for (OnGroupChangeListener listener : mListeners) { + for (OnGroupChangeListener listener : mGroupChangeListeners) { listener.onGroupsChanged(); } } @@ -607,7 +613,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State onEntryRemovedInternal(entry, entry.getSbn()); mIsolatedEntries.remove(sbn.getKey()); onEntryAddedInternal(entry); - for (OnGroupChangeListener listener : mListeners) { + for (OnGroupChangeListener listener : mGroupChangeListeners) { listener.onGroupsChanged(); } } @@ -618,12 +624,16 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State || notificationGroup.summary.isGroupNotFullyVisible(); } + /** + * Directly set the heads up manager to avoid circular dependencies + */ public void setHeadsUpManager(HeadsUpManager headsUpManager) { mHeadsUpManager = headsUpManager; } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("GroupManager state:"); + pw.println("GroupManagerLegacy state:"); pw.println(" number of groups: " + mGroupMap.size()); for (Map.Entry<String, NotificationGroup> entry : mGroupMap.entrySet()) { pw.println("\n key: " + entry.getKey()); pw.println(entry.getValue()); @@ -640,6 +650,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State setStatusBarState(newState); } + /** + * Represents a notification group in the notification shade. + */ public static class NotificationGroup { public final HashMap<String, NotificationEntry> children = new HashMap<>(); public NotificationEntry summary; @@ -659,24 +672,29 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State result += "\n children size: " + children.size(); for (NotificationEntry child : children.values()) { result += "\n " + child.getSbn() - + (child.getDebugThrowable() != null - ? Log.getStackTraceString(child.getDebugThrowable()) - : ""); + + (child.getDebugThrowable() != null + ? Log.getStackTraceString(child.getDebugThrowable()) + : ""); } result += "\n summary suppressed: " + suppressed; return result; } } + /** + * Listener for group changes not including group expansion changes which are handled by + * {@link OnGroupExpansionChangeListener}. + */ public interface OnGroupChangeListener { - /** * A new group has been created. * * @param group the group that was created * @param groupKey the group's key */ - default void onGroupCreated(NotificationGroup group, String groupKey) {} + default void onGroupCreated( + NotificationGroup group, + String groupKey) {} /** * A group has been removed. @@ -684,7 +702,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State * @param group the group that was removed * @param groupKey the group's key */ - default void onGroupRemoved(NotificationGroup group, String groupKey) {} + default void onGroupRemoved( + NotificationGroup group, + String groupKey) {} /** * The suppression of a group has changed. @@ -692,16 +712,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State * @param group the group that has changed * @param suppressed true if the group is now suppressed, false o/w */ - default void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) {} - - /** - * The expansion of a group has changed. - * - * @param changedRow the row for which the expansion has changed, which is also the summary - * @param expanded a boolean indicating the new expanded state - */ - default void onGroupExpansionChanged(ExpandableNotificationRow changedRow, - boolean expanded) {} + default void onGroupSuppressionChanged( + NotificationGroup group, + boolean suppressed) {} /** * A group of children just received a summary notification and should therefore become diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java index 8b803b517f14..18806effc545 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java @@ -20,11 +20,10 @@ import android.app.Notification; import android.app.NotificationManager; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import java.util.List; @@ -39,14 +38,14 @@ import javax.inject.Inject; @SysUISingleton public class HighPriorityProvider { private final PeopleNotificationIdentifier mPeopleNotificationIdentifier; - private final NotificationGroupManager mGroupManager; + private final GroupMembershipManager mGroupMembershipManager; @Inject public HighPriorityProvider( PeopleNotificationIdentifier peopleNotificationIdentifier, - NotificationGroupManager groupManager) { + GroupMembershipManager groupManager) { mPeopleNotificationIdentifier = peopleNotificationIdentifier; - mGroupManager = groupManager; + mGroupMembershipManager = groupManager; } /** @@ -81,20 +80,15 @@ public class HighPriorityProvider { private boolean hasHighPriorityChild(ListEntry entry) { - List<NotificationEntry> children = null; - - if (entry instanceof GroupEntry) { - // New notification pipeline - children = ((GroupEntry) entry).getChildren(); - } else if (entry.getRepresentativeEntry() != null - && mGroupManager.isGroupSummary(entry.getRepresentativeEntry().getSbn())) { - // Old notification pipeline - children = mGroupManager.getChildren(entry.getRepresentativeEntry().getSbn()); + if (entry instanceof NotificationEntry + && !mGroupMembershipManager.isGroupSummary((NotificationEntry) entry)) { + return false; } + List<NotificationEntry> children = mGroupMembershipManager.getChildren(entry); if (children != null) { for (NotificationEntry child : children) { - if (isHighPriority(child)) { + if (child != entry && isHighPriority(child)) { return true; } } @@ -122,8 +116,8 @@ public class HighPriorityProvider { } private boolean isPeopleNotification(NotificationEntry entry) { - return mPeopleNotificationIdentifier.getPeopleNotificationType( - entry.getSbn(), entry.getRanking()) != PeopleNotificationIdentifier.TYPE_NON_PERSON; + return mPeopleNotificationIdentifier.getPeopleNotificationType(entry) + != PeopleNotificationIdentifier.TYPE_NON_PERSON; } private boolean hasUserSetImportance(NotificationEntry entry) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java new file mode 100644 index 000000000000..d2df07ed7864 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.render; + +import com.android.systemui.Dumpable; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; + +/** + * Tracks expanded notification states for groups. This expanded state should not be confused by the + * expanded/collapsed state of a single notification which is tracked within each + * ExpandableNotificationRow. + */ +public interface GroupExpansionManager extends Dumpable { + + /** + * Register a listener for group expansion changes + */ + void registerGroupExpansionChangeListener(OnGroupExpansionChangeListener listener); + + /** + * Whether the group associated with this notification is expanded. + * If this notification is not part of a group, it will always return false. + */ + boolean isGroupExpanded(NotificationEntry entry); + + /** + * Set whether the group associated with this notification is expanded or not. + */ + void setGroupExpanded(NotificationEntry entry, boolean expanded); + + /** @return group expansion state after toggling. */ + boolean toggleGroupExpansion(NotificationEntry entry); + + /** + * Set expanded=false for all groups + */ + void collapseGroups(); + + /** + * Listener for group expansion changes. + */ + interface OnGroupExpansionChangeListener { + /** + * The expansion of a group has changed. + * + * @param changedRow the row for which the expansion has changed, which is also the summary + * @param expanded a boolean indicating the new expanded state + */ + void onGroupExpansionChange(ExpandableNotificationRow changedRow, boolean expanded); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java new file mode 100644 index 000000000000..b9aa26f75c9b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.render; + +import com.android.systemui.statusbar.notification.collection.GroupEntry; +import com.android.systemui.statusbar.notification.collection.ListEntry; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.coordinator.Coordinator; +import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.HashSet; +import java.util.Set; + +/** + * Provides grouping information for notification entries including information about a group's + * expanded state. + */ +public class GroupExpansionManagerImpl implements GroupExpansionManager, Coordinator { + private final GroupMembershipManager mGroupMembershipManager; + private final Set<OnGroupExpansionChangeListener> mOnGroupChangeListeners = new HashSet<>(); + + // Set of summary keys whose groups are expanded + private final Set<NotificationEntry> mExpandedGroups = new HashSet<>(); + + public GroupExpansionManagerImpl(GroupMembershipManager groupMembershipManager) { + mGroupMembershipManager = groupMembershipManager; + } + + /** + * Cleanup entries from mExpandedGroups that no longer exist in the pipeline. + */ + private final OnBeforeRenderListListener mNotifTracker = (entries) -> { + final Set<NotificationEntry> renderingSummaries = new HashSet<>(); + for (ListEntry entry : entries) { + if (entry instanceof GroupEntry) { + renderingSummaries.add(entry.getRepresentativeEntry()); + } + } + mExpandedGroups.removeIf(expandedGroup -> !renderingSummaries.contains(expandedGroup)); + }; + + @Override + public void attach(NotifPipeline pipeline) { + pipeline.addOnBeforeRenderListListener(mNotifTracker); + } + + @Override + public void registerGroupExpansionChangeListener(OnGroupExpansionChangeListener listener) { + mOnGroupChangeListeners.add(listener); + } + + @Override + public boolean isGroupExpanded(NotificationEntry entry) { + return mExpandedGroups.contains(mGroupMembershipManager.getGroupSummary(entry)); + } + + @Override + public void setGroupExpanded(NotificationEntry entry, boolean expanded) { + final NotificationEntry groupSummary = mGroupMembershipManager.getGroupSummary(entry); + if (expanded) { + mExpandedGroups.add(groupSummary); + } else { + mExpandedGroups.remove(groupSummary); + } + + sendOnGroupExpandedChange(entry, expanded); + } + + @Override + public boolean toggleGroupExpansion(NotificationEntry entry) { + setGroupExpanded(entry, !isGroupExpanded(entry)); + return isGroupExpanded(entry); + } + + @Override + public void collapseGroups() { + for (NotificationEntry entry : mExpandedGroups) { + setGroupExpanded(entry, false); + } + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("NotificationEntryExpansion state:"); + pw.println(" # expanded groups: " + mExpandedGroups.size()); + for (NotificationEntry entry : mExpandedGroups) { + pw.println(" summary key of expanded group: " + entry.getKey()); + } + } + + private void sendOnGroupExpandedChange(NotificationEntry entry, boolean expanded) { + for (OnGroupExpansionChangeListener listener : mOnGroupChangeListeners) { + listener.onGroupExpansionChange(entry.getRow(), expanded); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java new file mode 100644 index 000000000000..196cb8f26b22 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.render; + +import android.annotation.Nullable; + +import com.android.systemui.statusbar.notification.collection.ListEntry; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import java.util.List; + +/** + * Helper that determines the group states (parent, summary, children) of a notification. + */ +public interface GroupMembershipManager { + /** + * @return whether a given notification is a top level entry or is the summary in a group which + * has children + */ + boolean isGroupSummary(NotificationEntry entry); + + /** + * Get the summary of a specified status bar notification. For an isolated notification this + * returns itself. + */ + NotificationEntry getGroupSummary(NotificationEntry entry); + + /** + * Similar to {@link #getGroupSummary(NotificationEntry)} but doesn't get the visual summary + * but the logical summary, i.e when a child is isolated, it still returns the summary as if + * it wasn't isolated. + * TODO: remove this when migrating to the new pipeline, this is taken care of in the + * dismissal logic built into NotifCollection + */ + default NotificationEntry getLogicalGroupSummary(NotificationEntry entry) { + return getGroupSummary(entry); + } + + /** + * @return whether a given notification is a child in a group + */ + boolean isChildInGroup(NotificationEntry entry); + + /** + * Whether this is the only child in a group + * TODO: remove this when migrating to the new pipeline, this is taken care of in the + * dismissal logic built into NotifCollection + */ + boolean isOnlyChildInGroup(NotificationEntry entry); + + /** + * Get the children that are in the summary's group, not including those isolated. + * + * @param summary summary of a group + * @return list of the children + */ + @Nullable + List<NotificationEntry> getChildren(ListEntry summary); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java new file mode 100644 index 000000000000..c1f468a3072f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.render; + +import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY; + +import androidx.annotation.Nullable; + +import com.android.systemui.statusbar.notification.collection.GroupEntry; +import com.android.systemui.statusbar.notification.collection.ListEntry; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import java.util.List; + +/** + * ShadeListBuilder groups notifications from system server. This manager translates + * ShadeListBuilder's method of grouping to be used within SystemUI. + */ +public class GroupMembershipManagerImpl implements GroupMembershipManager { + @Override + public boolean isGroupSummary(NotificationEntry entry) { + return getGroupSummary(entry) == entry; + } + + @Override + public NotificationEntry getGroupSummary(NotificationEntry entry) { + if (isEntryTopLevel(entry) || entry.getParent() == null) { + return null; + } + + return entry.getParent().getRepresentativeEntry(); + } + + @Override + public boolean isChildInGroup(NotificationEntry entry) { + return !isEntryTopLevel(entry); + } + + @Override + public boolean isOnlyChildInGroup(NotificationEntry entry) { + if (entry.getParent() == null) { + return false; + } + + return entry.getParent().getChildren().size() == 1; + } + + @Nullable + @Override + public List<NotificationEntry> getChildren(ListEntry entry) { + if (entry instanceof GroupEntry) { + return ((GroupEntry) entry).getChildren(); + } + + if (isGroupSummary(entry.getRepresentativeEntry())) { + // maybe we were actually passed the summary + return entry.getRepresentativeEntry().getParent().getChildren(); + } + + return null; + } + + private boolean isEntryTopLevel(NotificationEntry entry) { + return entry.getParent() == ROOT_ENTRY; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt index 3c35b7bd8472..5243854ea412 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt @@ -24,7 +24,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.ShadeListBuilder import com.android.systemui.statusbar.notification.stack.NotificationListContainer import com.android.systemui.statusbar.phone.NotificationIconAreaController -import java.lang.RuntimeException import javax.inject.Inject /** 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 f3ed95bd2d76..e2aae64ce220 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 @@ -50,10 +50,15 @@ import com.android.systemui.statusbar.notification.collection.coordinator.Visual import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.OnUserInteractionCallbackImplLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl; import com.android.systemui.statusbar.notification.init.NotificationsControllerStub; @@ -67,7 +72,6 @@ import com.android.systemui.statusbar.notification.row.NotificationBlockingHelpe import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.leak.LeakDetector; @@ -91,7 +95,7 @@ public interface NotificationsModule { @Provides static NotificationEntryManager provideNotificationEntryManager( NotificationEntryManagerLogger logger, - NotificationGroupManager groupManager, + NotificationGroupManagerLegacy groupManager, NotificationRankingManager rankingManager, NotificationEntryManager.KeyguardEnvironment keyguardEnvironment, FeatureFlags featureFlags, @@ -206,6 +210,29 @@ public interface NotificationsModule { context, notificationGutsManager, notificationEntryManager, metricsLogger); } + /** Provides an instance of {@link GroupMembershipManager} */ + @SysUISingleton + @Provides + static GroupMembershipManager provideGroupMembershipManager( + FeatureFlags featureFlags, + Lazy<NotificationGroupManagerLegacy> groupManagerLegacy) { + return featureFlags.isNewNotifPipelineRenderingEnabled() + ? new GroupMembershipManagerImpl() + : groupManagerLegacy.get(); + } + + /** Provides an instance of {@link GroupExpansionManager} */ + @SysUISingleton + @Provides + static GroupExpansionManager provideGroupExpansionManager( + FeatureFlags featureFlags, + Lazy<GroupMembershipManager> groupMembershipManager, + Lazy<NotificationGroupManagerLegacy> groupManagerLegacy) { + return featureFlags.isNewNotifPipelineRenderingEnabled() + ? new GroupExpansionManagerImpl(groupMembershipManager.get()) + : groupManagerLegacy.get(); + } + /** Initializes the notification data pipeline (can be disabled via config). */ @SysUISingleton @Provides diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index 6460892952e7..9fb292878553 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -30,12 +30,12 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.TargetSdkResolver import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy import com.android.systemui.statusbar.notification.interruption.HeadsUpController import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer import com.android.systemui.statusbar.notification.stack.NotificationListContainer import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper -import com.android.systemui.statusbar.phone.NotificationGroupManager import com.android.systemui.statusbar.phone.StatusBar import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.HeadsUpManager @@ -65,7 +65,7 @@ class NotificationsControllerImpl @Inject constructor( private val deviceProvisionedController: DeviceProvisionedController, private val notificationRowBinder: NotificationRowBinderImpl, private val remoteInputUriController: RemoteInputUriController, - private val groupManager: NotificationGroupManager, + private val groupManagerLegacy: Lazy<NotificationGroupManagerLegacy>, private val groupAlertTransferHelper: NotificationGroupAlertTransferHelper, private val headsUpManager: HeadsUpManager, private val headsUpController: HeadsUpController, @@ -111,11 +111,11 @@ class NotificationsControllerImpl @Inject constructor( } else { targetSdkResolver.initialize(entryManager) remoteInputUriController.attach(entryManager) - groupAlertTransferHelper.bind(entryManager, groupManager) - headsUpManager.addListener(groupManager) + groupAlertTransferHelper.bind(entryManager, groupManagerLegacy.get()) + headsUpManager.addListener(groupManagerLegacy.get()) headsUpManager.addListener(groupAlertTransferHelper) headsUpController.attach(entryManager, headsUpManager) - groupManager.setHeadsUpManager(headsUpManager) + groupManagerLegacy.get().setHeadsUpManager(headsUpManager) groupAlertTransferHelper.setHeadsUpManager(headsUpManager) entryManager.attach(notificationListener) @@ -131,7 +131,6 @@ class NotificationsControllerImpl @Inject constructor( if (dumpTruck) { entryManager.dump(pw, " ") } - groupManager.dump(fd, pw, args) } // TODO: Convert all functions below this line into listeners instead of public methods diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt index 743bf332fc9d..99b2fcc9d610 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt @@ -214,7 +214,7 @@ class PeopleHubDataSourceImpl @Inject constructor( } private fun NotificationEntry.extractPerson(): PersonModel? { - val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking) + val type = peopleNotificationIdentifier.getPeopleNotificationType(this) if (type == TYPE_NON_PERSON) { return null } @@ -249,7 +249,7 @@ class PeopleHubDataSourceImpl @Inject constructor( private fun NotificationEntry.extractPersonKey(): PersonKey? { // TODO migrate to shortcut id when snoozing is conversation wide - val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking) + val type = peopleNotificationIdentifier.getPeopleNotificationType(this) return if (type != TYPE_NON_PERSON) key else null } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt index 1ac2cb5a36d5..0d92616767f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt @@ -20,12 +20,13 @@ import android.annotation.IntDef import android.service.notification.NotificationListenerService.Ranking import android.service.notification.StatusBarNotification import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON -import com.android.systemui.statusbar.phone.NotificationGroupManager import javax.inject.Inject import kotlin.math.max @@ -40,10 +41,12 @@ interface PeopleNotificationIdentifier { * that users shortcuts. */ @PeopleNotificationType - fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int + fun getPeopleNotificationType(entry: NotificationEntry): Int - fun compareTo(@PeopleNotificationType a: Int, - @PeopleNotificationType b: Int): Int + fun compareTo( + @PeopleNotificationType a: Int, + @PeopleNotificationType b: Int + ): Int companion object { @@ -62,24 +65,27 @@ interface PeopleNotificationIdentifier { @SysUISingleton class PeopleNotificationIdentifierImpl @Inject constructor( private val personExtractor: NotificationPersonExtractor, - private val groupManager: NotificationGroupManager + private val groupManager: GroupMembershipManager ) : PeopleNotificationIdentifier { @PeopleNotificationType - override fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int = - when (val type = ranking.personTypeInfo) { + override fun getPeopleNotificationType(entry: NotificationEntry): Int = + when (val type = entry.ranking.personTypeInfo) { TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON else -> { - when (val type = upperBound(type, extractPersonTypeInfo(sbn))) { + when (val type = upperBound(type, extractPersonTypeInfo(entry.sbn))) { TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON - else -> upperBound(type, getPeopleTypeOfSummary(sbn)) + else -> upperBound(type, getPeopleTypeOfSummary(entry)) } } } - override fun compareTo(@PeopleNotificationType a: Int, - @PeopleNotificationType b: Int): Int { - return b.compareTo(a); + override fun compareTo( + @PeopleNotificationType a: Int, + @PeopleNotificationType b: Int + ): Int + { + return b.compareTo(a) } /** @@ -105,14 +111,14 @@ class PeopleNotificationIdentifierImpl @Inject constructor( private fun extractPersonTypeInfo(sbn: StatusBarNotification) = if (personExtractor.isPersonNotification(sbn)) TYPE_PERSON else TYPE_NON_PERSON - private fun getPeopleTypeOfSummary(statusBarNotification: StatusBarNotification): Int { - if (!groupManager.isSummaryOfGroup(statusBarNotification)) { + private fun getPeopleTypeOfSummary(entry: NotificationEntry): Int { + if (!groupManager.isGroupSummary(entry)) { return TYPE_NON_PERSON } - val childTypes = groupManager.getChildren(statusBarNotification) + val childTypes = groupManager.getChildren(entry) ?.asSequence() - ?.map { getPeopleNotificationType(it.sbn, it.ranking) } + ?.map { getPeopleNotificationType(it) } ?: return TYPE_NON_PERSON var groupType = TYPE_NON_PERSON diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 46b497339d94..89f720535402 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -86,6 +86,8 @@ import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.logging.NotificationCounters; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; @@ -97,7 +99,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationChildrenCon import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.SwipeableView; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions; @@ -220,7 +221,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private boolean mNeedsRedaction; private boolean mLastChronometerRunning = true; private ViewStub mChildrenContainerStub; - private NotificationGroupManager mGroupManager; + private GroupMembershipManager mGroupMembershipManager; + private GroupExpansionManager mGroupExpansionManager; private boolean mChildrenExpanded; private boolean mIsSummaryWithChildren; private NotificationChildrenContainer mChildrenContainer; @@ -269,10 +271,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @Override public void onClick(View v) { if (!shouldShowPublic() && (!mIsLowPriority || isExpanded()) - && mGroupManager.isSummaryOfGroup(mEntry.getSbn())) { + && mGroupMembershipManager.isGroupSummary(mEntry)) { mGroupExpansionChanging = true; - final boolean wasExpanded = mGroupManager.isGroupExpanded(mEntry.getSbn()); - boolean nowExpanded = mGroupManager.toggleGroupExpansion(mEntry.getSbn()); + final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry); + boolean nowExpanded = mGroupExpansionManager.toggleGroupExpansion(mEntry); mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded); MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER, nowExpanded); @@ -527,8 +529,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } private boolean isConversation() { - return mPeopleNotificationIdentifier - .getPeopleNotificationType(mEntry.getSbn(), mEntry.getRanking()) + return mPeopleNotificationIdentifier.getPeopleNotificationType(mEntry) != PeopleNotificationIdentifier.TYPE_NON_PERSON; } @@ -820,7 +821,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * @return whether this notification is the only child in the group summary */ public boolean isOnlyChildInGroup() { - return mGroupManager.isOnlyChildInGroup(mEntry.getSbn()); + return mGroupMembershipManager.isOnlyChildInGroup(mEntry); } public ExpandableNotificationRow getNotificationParent() { @@ -1425,8 +1426,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void performDismiss(boolean fromAccessibility) { if (isOnlyChildInGroup()) { - NotificationEntry groupSummary = - mGroupManager.getLogicalGroupSummary(mEntry.getSbn()); + NotificationEntry groupSummary = mGroupMembershipManager.getLogicalGroupSummary(mEntry); if (groupSummary.isClearable()) { // If this is the only child in the group, dismiss the group, but don't try to show // the blocking helper affordance! @@ -1579,7 +1579,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView String notificationKey, ExpansionLogger logger, KeyguardBypassController bypassController, - NotificationGroupManager groupManager, + GroupMembershipManager groupMembershipManager, + GroupExpansionManager groupExpansionManager, HeadsUpManager headsUpManager, RowContentBindStage rowContentBindStage, OnExpandClickListener onExpandClickListener, @@ -1600,8 +1601,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mLogger = logger; mLoggingKey = notificationKey; mBypassController = bypassController; - mGroupManager = groupManager; - mPrivateLayout.setGroupManager(groupManager); + mGroupMembershipManager = groupMembershipManager; + mGroupExpansionManager = groupExpansionManager; + mPrivateLayout.setGroupMembershipManager(groupMembershipManager); mHeadsUpManager = headsUpManager; mRowContentBindStage = rowContentBindStage; mOnExpandClickListener = onExpandClickListener; @@ -2184,8 +2186,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mFalsingManager.setNotificationExpanded(); if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion && !mChildrenContainer.showingAsLowPriority()) { - final boolean wasExpanded = mGroupManager.isGroupExpanded(mEntry.getSbn()); - mGroupManager.setGroupExpanded(mEntry.getSbn(), userExpanded); + final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry); + mGroupExpansionManager.setGroupExpanded(mEntry, userExpanded); onExpansionChanged(true /* userAction */, wasExpanded); return; } @@ -2328,7 +2330,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @Override public boolean isGroupExpanded() { - return mGroupManager.isGroupExpanded(mEntry.getSbn()); + return mGroupExpansionManager.isGroupExpanded(mEntry); } private void onAttachedChildrenCountChanged() { @@ -2574,7 +2576,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void makeActionsVisibile() { setUserExpanded(true, true); if (isChildInGroup()) { - mGroupManager.setGroupExpanded(mEntry.getSbn(), true); + mGroupExpansionManager.setGroupExpanded(mEntry, true); } notifyHeightChanged(false /* needsAnimation */); } @@ -2867,7 +2869,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void onExpandedByGesture(boolean userExpanded) { int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER; - if (mGroupManager.isSummaryOfGroup(mEntry.getSbn())) { + if (mGroupMembershipManager.isGroupSummary(mEntry)) { event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER; } MetricsLogger.action(mContext, event, userExpanded); @@ -2912,7 +2914,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private void onExpansionChanged(boolean userAction, boolean wasExpanded) { boolean nowExpanded = isExpanded(); if (mIsSummaryWithChildren && (!mIsLowPriority || wasExpanded)) { - nowExpanded = mGroupManager.isGroupExpanded(mEntry.getSbn()); + nowExpanded = mGroupExpansionManager.isGroupExpanded(mEntry); } if (nowExpanded != wasExpanded) { updateShelfIconColor(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java index ce760cb525f9..05d9fe757dfd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java @@ -31,6 +31,8 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.collection.render.NodeController; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; @@ -39,7 +41,6 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationKey; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.time.SystemClock; @@ -62,7 +63,8 @@ public class ExpandableNotificationRowController implements NodeController { private final String mAppName; private final String mNotificationKey; private final KeyguardBypassController mKeyguardBypassController; - private final NotificationGroupManager mNotificationGroupManager; + private final GroupMembershipManager mGroupMembershipManager; + private final GroupExpansionManager mGroupExpansionManager; private final RowContentBindStage mRowContentBindStage; private final NotificationLogger mNotificationLogger; private final HeadsUpManager mHeadsUpManager; @@ -85,7 +87,8 @@ public class ExpandableNotificationRowController implements NodeController { NotificationMediaManager mediaManager, PluginManager pluginManager, SystemClock clock, @AppName String appName, @NotificationKey String notificationKey, KeyguardBypassController keyguardBypassController, - NotificationGroupManager notificationGroupManager, + GroupMembershipManager groupMembershipManager, + GroupExpansionManager groupExpansionManager, RowContentBindStage rowContentBindStage, NotificationLogger notificationLogger, HeadsUpManager headsUpManager, ExpandableNotificationRow.OnExpandClickListener onExpandClickListener, @@ -103,7 +106,8 @@ public class ExpandableNotificationRowController implements NodeController { mAppName = appName; mNotificationKey = notificationKey; mKeyguardBypassController = keyguardBypassController; - mNotificationGroupManager = notificationGroupManager; + mGroupMembershipManager = groupMembershipManager; + mGroupExpansionManager = groupExpansionManager; mRowContentBindStage = rowContentBindStage; mNotificationLogger = notificationLogger; mHeadsUpManager = headsUpManager; @@ -128,7 +132,8 @@ public class ExpandableNotificationRowController implements NodeController { mNotificationKey, mExpansionLogger, mKeyguardBypassController, - mNotificationGroupManager, + mGroupMembershipManager, + mGroupExpansionManager, mHeadsUpManager, mRowContentBindStage, mOnExpandClickListener, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index c7e44c5e8e0a..1de9308a40b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -28,9 +28,7 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; import android.provider.Settings; -import android.service.notification.StatusBarNotification; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; @@ -52,11 +50,10 @@ import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.TransformableView; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper; -import com.android.systemui.statusbar.notification.row.wrapper.NotificationTemplateViewWrapper; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.InflatedSmartReplies; import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions; import com.android.systemui.statusbar.policy.RemoteInputView; @@ -122,8 +119,8 @@ public class NotificationContentView extends FrameLayout { private int mSmallHeight; private int mHeadsUpHeight; private int mNotificationMaxHeight; - private StatusBarNotification mStatusBarNotification; - private NotificationGroupManager mGroupManager; + private NotificationEntry mNotificationEntry; + private GroupMembershipManager mGroupMembershipManager; private RemoteInputController mRemoteInputController; private Runnable mExpandedVisibleListener; private PeopleNotificationIdentifier mPeopleIdentifier; @@ -778,7 +775,7 @@ public class NotificationContentView extends FrameLayout { } private boolean isGroupExpanded() { - return mGroupManager.isGroupExpanded(mStatusBarNotification); + return mContainingNotification.isGroupExpanded(); } public void setClipTopAmount(int clipTopAmount) { @@ -908,10 +905,10 @@ public class NotificationContentView extends FrameLayout { public int getBackgroundColorForExpansionState() { // When expanding or user locked we want the new type, when collapsing we want // the original type - final int visibleType = (mContainingNotification.isGroupExpanded() - || mContainingNotification.isUserLocked()) - ? calculateVisibleType() - : getVisibleType(); + final int visibleType = ( + isGroupExpanded() || mContainingNotification.isUserLocked()) + ? calculateVisibleType() + : getVisibleType(); return getBackgroundColor(visibleType); } @@ -1145,7 +1142,7 @@ public class NotificationContentView extends FrameLayout { } public void onNotificationUpdated(NotificationEntry entry) { - mStatusBarNotification = entry.getSbn(); + mNotificationEntry = entry; mBeforeN = entry.targetSdk < Build.VERSION_CODES.N; updateAllSingleLineViews(); ExpandableNotificationRow row = entry.getRow(); @@ -1176,7 +1173,7 @@ public class NotificationContentView extends FrameLayout { if (mIsChildInGroup) { boolean isNewView = mSingleLineView == null; mSingleLineView = mHybridGroupManager.bindFromNotification( - mSingleLineView, mContractedChild, mStatusBarNotification, this); + mSingleLineView, mContractedChild, mNotificationEntry.getSbn(), this); if (isNewView) { updateViewVisibility(mVisibleType, VISIBLE_TYPE_SINGLELINE, mSingleLineView, mSingleLineView); @@ -1363,7 +1360,7 @@ public class NotificationContentView extends FrameLayout { return; } boolean isPersonWithShortcut = - mPeopleIdentifier.getPeopleNotificationType(entry.getSbn(), entry.getRanking()) + mPeopleIdentifier.getPeopleNotificationType(entry) >= PeopleNotificationIdentifier.TYPE_FULL_PERSON; boolean showButton = isBubblesEnabled() && isPersonWithShortcut @@ -1516,8 +1513,8 @@ public class NotificationContentView extends FrameLayout { } } - public void setGroupManager(NotificationGroupManager groupManager) { - mGroupManager = groupManager; + public void setGroupMembershipManager(GroupMembershipManager groupMembershipManager) { + mGroupMembershipManager = groupMembershipManager; } public void setRemoteInputController(RemoteInputController r) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java index 205cecc92e55..65a72cc0b76b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java @@ -24,7 +24,6 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.Nullable; -import android.app.Notification; import android.content.Context; import android.content.res.Resources; import android.graphics.Point; @@ -260,8 +259,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl } mFeedbackItem = createFeedbackItem(mContext); NotificationEntry entry = mParent.getEntry(); - int personNotifType = mPeopleNotificationIdentifier - .getPeopleNotificationType(entry.getSbn(), entry.getRanking()); + int personNotifType = mPeopleNotificationIdentifier.getPeopleNotificationType(entry); if (personNotifType == PeopleNotificationIdentifier.TYPE_PERSON) { mInfoItem = createPartialConversationItem(mContext); } else if (personNotifType >= PeopleNotificationIdentifier.TYPE_FULL_PERSON) { 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 3370773df807..60883f04c9e0 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 @@ -117,6 +117,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -129,8 +131,6 @@ import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; 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.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; @@ -233,7 +233,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private final StackScrollAlgorithm mStackScrollAlgorithm; private final AmbientState mAmbientState; - private NotificationGroupManager mGroupManager; + private GroupMembershipManager mGroupMembershipManager; + private GroupExpansionManager mGroupExpansionManager; private NotificationActivityStarter mNotificationActivityStarter; private HashSet<ExpandableView> mChildrenToAddAnimated = new HashSet<>(); private ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>(); @@ -415,7 +416,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable }; private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC); private boolean mPulsing; - private boolean mGroupExpandedForMeasure; private boolean mScrollable; private View mForcedScroll; @@ -560,7 +560,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable NotifPipeline notifPipeline, NotificationEntryManager entryManager, NotifCollection notifCollection, - UiEventLogger uiEventLogger + UiEventLogger uiEventLogger, + GroupMembershipManager groupMembershipManager, + GroupExpansionManager groupExpansionManager ) { super(context, attrs, 0, 0); Resources res = getResources(); @@ -636,6 +638,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } }); } + mGroupMembershipManager = groupMembershipManager; + mGroupExpansionManager = groupExpansionManager; mDynamicPrivacyController = dynamicPrivacyController; mStatusbarStateController = statusbarStateController; @@ -1440,7 +1444,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable ExpandableNotificationRow row = mTopHeadsUpEntry.getRow(); if (row.isChildInGroup()) { final NotificationEntry groupSummary = - mGroupManager.getGroupSummary(row.getEntry().getSbn()); + mGroupMembershipManager.getGroupSummary(row.getEntry()); if (groupSummary != null) { row = groupSummary.getRow(); } @@ -1617,9 +1621,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable NotificationEntry entry = row.getEntry(); if (!mIsExpanded && row.isHeadsUp() && row.isPinned() && mTopHeadsUpEntry.getRow() != row - && mGroupManager.getGroupSummary( - mTopHeadsUpEntry.getSbn()) - != entry) { + && mGroupMembershipManager.getGroupSummary(mTopHeadsUpEntry) != entry) { continue; } return row.getViewAtPosition(touchY - childTop); @@ -3017,8 +3019,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.ADAPTER) private boolean isChildInGroup(View child) { return child instanceof ExpandableNotificationRow - && mGroupManager.isChildInGroupWithSummary( - ((ExpandableNotificationRow) child).getEntry().getSbn()); + && mGroupMembershipManager.isChildInGroup( + ((ExpandableNotificationRow) child).getEntry()); } /** @@ -3083,6 +3085,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable return hasAddEvent; } + // TODO (b/162832756): remove since this won't happen in new pipeline (we prune groups in + // ShadeListBuilder) /** * @param child the child to query * @return whether a view is not a top level child but a child notification and that group is @@ -3093,7 +3097,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable if (child instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) child; NotificationEntry groupSummary = - mGroupManager.getGroupSummary(row.getEntry().getSbn()); + mGroupMembershipManager.getGroupSummary(row.getEntry()); if (groupSummary != null && groupSummary.getRow() != row) { return row.getVisibility() == View.INVISIBLE; } @@ -4349,7 +4353,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable if (changed) { mWillExpand = false; if (!mIsExpanded) { - mGroupManager.collapseAllGroups(); + mGroupExpansionManager.collapseGroups(); mExpandHelper.cancelImmediately(); } updateNotificationAnimationStates(); @@ -4886,12 +4890,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable this.mStatusBar = statusBar; } - @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setGroupManager(NotificationGroupManager groupManager) { - this.mGroupManager = groupManager; - mGroupManager.addOnGroupChangeListener(mOnGroupChangeListener); - } - @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) void requestAnimateEverything() { if (mIsExpanded && mAnimationsEnabled) { @@ -4990,17 +4988,29 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable public void removeContainerView(View v) { Assert.isMainThread(); removeView(v); + if (v instanceof ExpandableNotificationRow && !mController.isShowingEmptyShadeView()) { + mController.updateShowEmptyShadeView(); + updateFooter(); + } } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void addContainerView(View v) { Assert.isMainThread(); addView(v); + if (v instanceof ExpandableNotificationRow && mController.isShowingEmptyShadeView()) { + mController.updateShowEmptyShadeView(); + updateFooter(); + } } public void addContainerViewAt(View v, int index) { Assert.isMainThread(); addView(v, index); + if (v instanceof ExpandableNotificationRow && mController.isShowingEmptyShadeView()) { + mController.updateShowEmptyShadeView(); + updateFooter(); + } } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) @@ -5101,6 +5111,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable updateScrollability(); } + boolean isQsExpanded() { + return mQsExpanded; + } + @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void setQsExpansionFraction(float qsExpansionFraction) { mQsExpansionFraction = qsExpansionFraction; @@ -6296,39 +6310,22 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable public HeadsUpTouchHelper.Callback getHeadsUpCallback() { return mHeadsUpCallback; } - - @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - private final OnGroupChangeListener mOnGroupChangeListener = new OnGroupChangeListener() { - @Override - public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) { - boolean animated = !mGroupExpandedForMeasure && mAnimationsEnabled - && (mIsExpanded || changedRow.isPinned()); - if (animated) { - mExpandedGroupView = changedRow; - mNeedsAnimation = true; - } - changedRow.setChildrenExpanded(expanded, animated); - if (!mGroupExpandedForMeasure) { - onChildHeightChanged(changedRow, false /* needsAnimation */); - } - runAfterAnimationFinished(new Runnable() { - @Override - public void run() { - changedRow.onFinishedExpansionChange(); - } - }); - } - - @Override - public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) { - mStatusBar.requestNotificationUpdate("onGroupCreatedFromChildren"); + void onGroupExpandChanged(ExpandableNotificationRow changedRow, boolean expanded) { + boolean animated = mAnimationsEnabled && (mIsExpanded || changedRow.isPinned()); + if (animated) { + mExpandedGroupView = changedRow; + mNeedsAnimation = true; } + changedRow.setChildrenExpanded(expanded, animated); + onChildHeightChanged(changedRow, false /* needsAnimation */); - @Override - public void onGroupsChanged() { - mStatusBar.requestNotificationUpdate("onGroupsChanged"); - } - }; + runAfterAnimationFinished(new Runnable() { + @Override + public void run() { + changedRow.onFinishedExpansionChange(); + } + }); + } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) private ExpandHelper.Callback mExpandHelperCallback = new ExpandHelper.Callback() { 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 70892e0f9b38..a0b49aca6ded 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 @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.stack; import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; +import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import android.content.res.Resources; import android.graphics.Point; @@ -56,6 +57,10 @@ import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -67,7 +72,6 @@ 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.KeyguardBypassController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBar; @@ -117,6 +121,8 @@ public class NotificationStackScrollLayoutController { private NotificationStackScrollLayout mView; private boolean mFadeNotificationsOnDismiss; private NotificationSwipeHelper mSwipeHelper; + private boolean mShowEmptyShadeView; + private int mBarState; private final NotificationListContainerImpl mNotificationListContainer = new NotificationListContainerImpl(); @@ -127,6 +133,8 @@ public class NotificationStackScrollLayoutController { @Override public void onViewAttachedToWindow(View v) { mConfigurationController.addCallback(mConfigurationListener); + mZenModeController.addCallback(mZenModeControllerCallback); + mBarState = mStatusBarStateController.getState(); mStatusBarStateController.addCallback( mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER); } @@ -134,6 +142,7 @@ public class NotificationStackScrollLayoutController { @Override public void onViewDetachedFromWindow(View v) { mConfigurationController.removeCallback(mConfigurationListener); + mZenModeController.removeCallback(mZenModeControllerCallback); mStatusBarStateController.removeCallback(mStateListener); } }; @@ -154,11 +163,13 @@ public class NotificationStackScrollLayoutController { final ConfigurationListener mConfigurationListener = new ConfigurationListener() { @Override public void onDensityOrFontScaleChanged() { + updateShowEmptyShadeView(); mView.reinflateViews(); } @Override public void onOverlayChanged() { + updateShowEmptyShadeView(); mView.updateCornerRadius(); mView.reinflateViews(); } @@ -179,14 +190,15 @@ public class NotificationStackScrollLayoutController { @Override public void onStatePreChange(int oldState, int newState) { if (oldState == StatusBarState.SHADE_LOCKED - && newState == StatusBarState.KEYGUARD) { + && newState == KEYGUARD) { mView.requestAnimateEverything(); } } @Override public void onStateChanged(int newState) { - mView.setStatusBarState(newState); + mBarState = newState; + mView.setStatusBarState(mBarState); } @Override @@ -480,6 +492,14 @@ public class NotificationStackScrollLayoutController { } }; + private final ZenModeController.Callback mZenModeControllerCallback = + new ZenModeController.Callback() { + @Override + public void onZenChanged(int zen) { + updateShowEmptyShadeView(); + } + }; + @Inject public NotificationStackScrollLayoutController( @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, @@ -501,7 +521,9 @@ public class NotificationStackScrollLayoutController { @Main Resources resources, NotificationSwipeHelper.Builder notificationSwipeHelperBuilder, StatusBar statusBar, - ScrimController scrimController) { + ScrimController scrimController, + NotificationGroupManagerLegacy legacyGroupManager, + GroupExpansionManager groupManager) { mAllowLongPress = allowLongPress; mNotificationGutsManager = notificationGutsManager; mHeadsUpManager = headsUpManager; @@ -522,12 +544,28 @@ public class NotificationStackScrollLayoutController { mNotificationSwipeHelperBuilder = notificationSwipeHelperBuilder; mStatusBar = statusBar; mScrimController = scrimController; + groupManager.registerGroupExpansionChangeListener((changedRow, expanded) -> { + mView.onGroupExpandChanged(changedRow, expanded); + }); + + legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() { + @Override + public void onGroupCreatedFromChildren(NotificationGroup group) { + mStatusBar.requestNotificationUpdate("onGroupCreatedFromChildren"); + } + + @Override + public void onGroupsChanged() { + mStatusBar.requestNotificationUpdate("onGroupsChanged"); + } + }); } public void attach(NotificationStackScrollLayout view) { mView = view; mView.setController(this); mView.setTouchHandler(new TouchHandler()); + mView.setStatusBar(mStatusBar); mSwipeHelper = mNotificationSwipeHelperBuilder .setSwipeDirection(SwipeHelper.X) @@ -795,6 +833,7 @@ public class NotificationStackScrollLayoutController { public void setQsExpanded(boolean expanded) { mView.setQsExpanded(expanded); + updateShowEmptyShadeView(); } public void setScrollingEnabled(boolean enabled) { @@ -903,8 +942,21 @@ public class NotificationStackScrollLayoutController { return mView.getFooterViewHeightWithPadding(); } - public void updateEmptyShadeView(boolean visible) { - mView.updateEmptyShadeView(visible, mZenModeController.areNotificationsHiddenInShade()); + /** + * Update whether we should show the empty shade view (no notifications in the shade). + * If so, send the update to our view. + */ + public void updateShowEmptyShadeView() { + mShowEmptyShadeView = mBarState != KEYGUARD + && !mView.isQsExpanded() + && mView.getVisibleNotificationCount() == 0; + mView.updateEmptyShadeView( + mShowEmptyShadeView, + mZenModeController.areNotificationsHiddenInShade()); + } + + public boolean isShowingEmptyShadeView() { + return mShowEmptyShadeView; } public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { @@ -1012,14 +1064,6 @@ public class NotificationStackScrollLayoutController { mView.setNotificationPanelController(notificationPanelViewController); } - public void setStatusBar(StatusBar statusBar) { - mView.setStatusBar(statusBar); - } - - public void setGroupManager(NotificationGroupManager groupManager) { - mView.setGroupManager(groupManager); - } - public void setShelfController(NotificationShelfController notificationShelfController) { mView.setShelfController(notificationShelfController); } @@ -1095,6 +1139,7 @@ public class NotificationStackScrollLayoutController { } private class NotificationListContainerImpl implements NotificationListContainer { + @Override public void setChildTransferInProgress(boolean childTransferInProgress) { mView.setChildTransferInProgress(childTransferInProgress); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index 8092cb910b07..3827123f0160 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -33,6 +33,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController.StateList import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -55,7 +56,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, @VisibleForTesting final int mExtensionTime; private final KeyguardBypassController mBypassController; - private final NotificationGroupManager mGroupManager; + private final GroupMembershipManager mGroupMembershipManager; private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>(); private final int mAutoHeadsUpNotificationDecay; // TODO (b/162832756): remove visual stability manager when migrating to new pipeline @@ -101,7 +102,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, public HeadsUpManagerPhone(@NonNull final Context context, StatusBarStateController statusBarStateController, KeyguardBypassController bypassController, - NotificationGroupManager groupManager, + GroupMembershipManager groupMembershipManager, ConfigurationController configurationController) { super(context); Resources resources = mContext.getResources(); @@ -110,7 +111,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, R.integer.auto_heads_up_notification_decay); statusBarStateController.addCallback(mStatusBarStateListener); mBypassController = bypassController; - mGroupManager = groupManager; + mGroupMembershipManager = groupMembershipManager; updateResources(); configurationController.addCallback(new ConfigurationController.ConfigurationListener() { @@ -166,7 +167,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, } else { if (topEntry.isChildInGroup()) { final NotificationEntry groupSummary = - mGroupManager.getGroupSummary(topEntry.getSbn()); + mGroupMembershipManager.getGroupSummary(topEntry); if (groupSummary != null) { topEntry = groupSummary; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index b6a284c5e3c4..09034c0899f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -40,6 +40,8 @@ import com.android.keyguard.KeyguardSecurityView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.ViewMediatorCallback; +import com.android.keyguard.dagger.ContainerView; +import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.systemui.DejankUtils; import com.android.systemui.Dependency; import com.android.systemui.R; @@ -50,9 +52,12 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import java.io.PrintWriter; +import javax.inject.Inject; + /** * A class which manages the bouncer on the lockscreen. */ +@KeyguardBouncerScope public class KeyguardBouncer { private static final String TAG = "KeyguardBouncer"; @@ -95,8 +100,9 @@ public class KeyguardBouncer { private boolean mIsAnimatingAway; private boolean mIsScrimmed; + @Inject public KeyguardBouncer(Context context, ViewMediatorCallback callback, - LockPatternUtils lockPatternUtils, ViewGroup container, + LockPatternUtils lockPatternUtils, @ContainerView ViewGroup container, DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager, BouncerExpansionCallback expansionCallback, KeyguardStateController keyguardStateController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java index dd9c8207af06..3181f520dca2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java @@ -31,11 +31,11 @@ import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; import com.android.systemui.statusbar.notification.row.RowContentBindParams; import com.android.systemui.statusbar.notification.row.RowContentBindStage; -import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup; -import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener; import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; @@ -44,8 +44,8 @@ import java.util.ArrayList; import java.util.Objects; /** - * A helper class dealing with the alert interactions between {@link NotificationGroupManager} and - * {@link HeadsUpManager}. In particular, this class deals with keeping + * A helper class dealing with the alert interactions between {@link NotificationGroupManagerLegacy} + * and {@link HeadsUpManager}. In particular, this class deals with keeping * the correct notification in a group alerting based off the group suppression. */ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener, @@ -66,8 +66,8 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis private HeadsUpManager mHeadsUpManager; private final RowContentBindStage mRowContentBindStage; - private final NotificationGroupManager mGroupManager = - Dependency.get(NotificationGroupManager.class); + private final NotificationGroupManagerLegacy mGroupManager = + Dependency.get(NotificationGroupManagerLegacy.class); private NotificationEntryManager mEntryManager; @@ -83,7 +83,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis /** Causes the TransferHelper to register itself as a listener to the appropriate classes. */ public void bind(NotificationEntryManager entryManager, - NotificationGroupManager groupManager) { + NotificationGroupManagerLegacy groupManager) { if (mEntryManager != null) { throw new IllegalStateException("Already bound."); } @@ -95,7 +95,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis mEntryManager = entryManager; mEntryManager.addNotificationEntryListener(mNotificationEntryListener); - groupManager.addOnGroupChangeListener(mOnGroupChangeListener); + groupManager.registerGroupChangeListener(mOnGroupChangeListener); } /** @@ -128,7 +128,8 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis mIsDozing = isDozing; } - private final OnGroupChangeListener mOnGroupChangeListener = new OnGroupChangeListener() { + private final NotificationGroupManagerLegacy.OnGroupChangeListener mOnGroupChangeListener = + new NotificationGroupManagerLegacy.OnGroupChangeListener() { @Override public void onGroupCreated(NotificationGroup group, String groupKey) { mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group)); 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 1cd85e3b3cc1..169058a3da21 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -107,6 +107,8 @@ import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.ViewGroupFadeHelper; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; +import com.android.systemui.statusbar.notification.collection.render.ShadeViewManager; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; @@ -120,7 +122,6 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; -import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.InjectionInflationController; import java.io.FileDescriptor; @@ -168,9 +169,6 @@ public class NotificationPanelViewController extends PanelViewController { mOnHeadsUpChangedListener = new MyOnHeadsUpChangedListener(); private final HeightListener mHeightListener = new HeightListener(); - private final ZenModeControllerCallback - mZenModeControllerCallback = - new ZenModeControllerCallback(); private final ConfigurationListener mConfigurationListener = new ConfigurationListener(); private final StatusBarStateListener mStatusBarStateListener = new StatusBarStateListener(); private final ExpansionCallback mExpansionCallback = new ExpansionCallback(); @@ -178,7 +176,6 @@ public class NotificationPanelViewController extends PanelViewController { private final NotificationPanelView mView; private final MetricsLogger mMetricsLogger; private final ActivityManager mActivityManager; - private final ZenModeController mZenModeController; private final ConfigurationController mConfigurationController; private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder; private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; @@ -342,8 +339,6 @@ public class NotificationPanelViewController extends PanelViewController { private boolean mKeyguardStatusViewAnimating; private ValueAnimator mQsSizeChangeAnimator; - private boolean mShowEmptyShadeView; - private boolean mQsScrimEnabled = true; private boolean mQsTouchAboveFalsingThreshold; private int mQsFalsingThreshold; @@ -367,7 +362,8 @@ public class NotificationPanelViewController extends PanelViewController { setHeadsUpAnimatingAway(false); notifyBarPanelExpansionChanged(); }; - private NotificationGroupManager mGroupManager; + // TODO (b/162832756): once migrated to the new pipeline, delete legacy group manager + private NotificationGroupManagerLegacy mGroupManager; private boolean mShowIconsWhenExpanded; private int mIndicationBottomPadding; private int mAmbientIndicationBottomPadding; @@ -505,7 +501,7 @@ public class NotificationPanelViewController extends PanelViewController { LatencyTracker latencyTracker, PowerManager powerManager, AccessibilityManager accessibilityManager, @DisplayId int displayId, KeyguardUpdateMonitor keyguardUpdateMonitor, MetricsLogger metricsLogger, - ActivityManager activityManager, ZenModeController zenModeController, + ActivityManager activityManager, ConfigurationController configurationController, FlingAnimationUtils.Builder flingAnimationUtilsBuilder, StatusBarTouchableRegionManager statusBarTouchableRegionManager, @@ -514,20 +510,21 @@ public class NotificationPanelViewController extends PanelViewController { BiometricUnlockController biometricUnlockController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, NotificationStackScrollLayoutController notificationStackScrollLayoutController, - NotificationIconAreaController notificationIconAreaController, - KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) { + KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, + NotificationGroupManagerLegacy groupManager, + NotificationIconAreaController notificationIconAreaController) { super(view, falsingManager, dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, vibratorHelper, latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager); mView = view; mMetricsLogger = metricsLogger; mActivityManager = activityManager; - mZenModeController = zenModeController; mConfigurationController = configurationController; mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder; mMediaHierarchyManager = mediaHierarchyManager; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mNotificationStackScrollLayoutController = notificationStackScrollLayoutController; + mGroupManager = groupManager; mNotificationIconAreaController = notificationIconAreaController; mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; mView.setWillNotDraw(!DEBUG); @@ -724,8 +721,6 @@ public class NotificationPanelViewController extends PanelViewController { } private void reInflateViews() { - updateShowEmptyShadeView(); - // Re-inflate the status view group. int index = mView.indexOfChild(mKeyguardStatusView); mView.removeView(mKeyguardStatusView); @@ -1727,7 +1722,6 @@ public class NotificationPanelViewController extends PanelViewController { mNotificationStackScrollLayoutController.setScrollingEnabled( mBarState != KEYGUARD && (!mQsExpanded || mQsExpansionFromOverscroll)); - updateEmptyShadeView(); mQsNavbarScrim.setVisibility( mBarState == StatusBarState.SHADE && mQsExpanded && !mStackScrollerOverscrolling @@ -2145,7 +2139,7 @@ public class NotificationPanelViewController extends PanelViewController { // it in expanded QS state as well so we don't run into troubles when fading the view in/out // and expanding/collapsing the whole panel from/to quick settings. if (mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0 - && mShowEmptyShadeView) { + && mNotificationStackScrollLayoutController.isShowingEmptyShadeView()) { notificationHeight = mNotificationStackScrollLayoutController.getEmptyShadeViewHeight(); } int maxQsHeight = mQsMaxExpansionHeight; @@ -2561,17 +2555,6 @@ public class NotificationPanelViewController extends PanelViewController { return mDozing; } - public void showEmptyShadeView(boolean emptyShadeViewVisible) { - mShowEmptyShadeView = emptyShadeViewVisible; - updateEmptyShadeView(); - } - - private void updateEmptyShadeView() { - // Hide "No notifications" in QS. - mNotificationStackScrollLayoutController.updateEmptyShadeView( - mShowEmptyShadeView && !mQsExpanded); - } - public void setQsScrimEnabled(boolean qsScrimEnabled) { boolean changed = mQsScrimEnabled != qsScrimEnabled; mQsScrimEnabled = qsScrimEnabled; @@ -2873,10 +2856,6 @@ public class NotificationPanelViewController extends PanelViewController { return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName()); } - private void setGroupManager(NotificationGroupManager groupManager) { - mGroupManager = groupManager; - } - public boolean hideStatusBarIconsWhenExpanded() { if (mLaunchingNotification) { return mHideIconsDuringNotificationLaunch; @@ -3078,22 +3057,21 @@ public class NotificationPanelViewController extends PanelViewController { return mNotificationStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL); } - private void updateShowEmptyShadeView() { - boolean - showEmptyShadeView = - mBarState != KEYGUARD && !mEntryManager.hasActiveNotifications(); - showEmptyShadeView(showEmptyShadeView); - } - public RemoteInputController.Delegate createRemoteInputDelegate() { return mNotificationStackScrollLayoutController.createDelegate(); } - void updateNotificationViews(String reason) { + /** + * Updates the notification views' sections and status bar icons. This is + * triggered by the NotificationPresenter whenever there are changes to the underlying + * notification data being displayed. In the new notification pipeline, this is handled in + * {@link ShadeViewManager}. + */ + public void updateNotificationViews(String reason) { mNotificationStackScrollLayoutController.updateSectionBoundaries(reason); mNotificationStackScrollLayoutController.updateSpeedBumpIndex(); mNotificationStackScrollLayoutController.updateFooter(); - updateShowEmptyShadeView(); + mNotificationIconAreaController.updateNotificationIcons(createVisibleEntriesList()); } @@ -3139,15 +3117,10 @@ public class NotificationPanelViewController extends PanelViewController { */ public void initDependencies( StatusBar statusBar, - NotificationGroupManager groupManager, NotificationShelfController notificationShelfController) { setStatusBar(statusBar); - setGroupManager(mGroupManager); mNotificationStackScrollLayoutController.setNotificationPanelController(this); - mNotificationStackScrollLayoutController.setStatusBar(statusBar); - mNotificationStackScrollLayoutController.setGroupManager(groupManager); mNotificationStackScrollLayoutController.setShelfController(notificationShelfController); - updateShowEmptyShadeView(); mNotificationShelfController = notificationShelfController; updateMaxDisplayedNotifications(true); } @@ -3602,20 +3575,8 @@ public class NotificationPanelViewController extends PanelViewController { } } - private class ZenModeControllerCallback implements ZenModeController.Callback { - @Override - public void onZenChanged(int zen) { - updateShowEmptyShadeView(); - } - } - private class ConfigurationListener implements ConfigurationController.ConfigurationListener { @Override - public void onDensityOrFontScaleChanged() { - updateShowEmptyShadeView(); - } - - @Override public void onThemeChanged() { final int themeResId = mView.getContext().getThemeResId(); if (mThemeResId == themeResId) { @@ -3712,7 +3673,6 @@ public class NotificationPanelViewController extends PanelViewController { public void onViewAttachedToWindow(View v) { FragmentHostManager.get(mView).addTagListener(QS.TAG, mFragmentListener); mStatusBarStateController.addCallback(mStatusBarStateListener); - mZenModeController.addCallback(mZenModeControllerCallback); mConfigurationController.addCallback(mConfigurationListener); mUpdateMonitor.registerCallback(mKeyguardUpdateCallback); // Theme might have changed between inflating this view and attaching it to the @@ -3725,7 +3685,6 @@ public class NotificationPanelViewController extends PanelViewController { public void onViewDetachedFromWindow(View v) { FragmentHostManager.get(mView).removeTagListener(QS.TAG, mFragmentListener); mStatusBarStateController.removeCallback(mStatusBarStateListener); - mZenModeController.removeCallback(mZenModeControllerCallback); mConfigurationController.removeCallback(mConfigurationListener); mUpdateMonitor.removeCallback(mKeyguardUpdateCallback); } 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 58828797cfde..298672769b56 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -699,7 +699,6 @@ public class StatusBar extends SystemUI implements DemoMode, SysuiStatusBarStateController statusBarStateController, VibratorHelper vibratorHelper, BubbleController bubbleController, - NotificationGroupManager groupManager, VisualStabilityManager visualStabilityManager, DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, @@ -780,7 +779,6 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarStateController = statusBarStateController; mVibratorHelper = vibratorHelper; mBubbleController = bubbleController; - mGroupManager = groupManager; mVisualStabilityManager = visualStabilityManager; mDeviceProvisionedController = deviceProvisionedController; mNavigationBarController = navigationBarController; @@ -1159,7 +1157,6 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationPanelViewController.initDependencies( this, - mGroupManager, mNotificationShelfController); BackDropView backdrop = mNotificationShadeWindowView.findViewById(R.id.backdrop); @@ -1506,9 +1503,8 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarKeyguardViewManager.registerStatusBar( /* statusBar= */ this, getBouncerContainer(), mNotificationPanelViewController, mBiometricUnlockController, - mDismissCallbackRegistry, mNotificationShadeWindowView.findViewById(R.id.lock_icon_container), - mStackScroller, mKeyguardBypassController, mFalsingManager); + mStackScroller, mKeyguardBypassController); mKeyguardIndicationController .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); @@ -4084,8 +4080,6 @@ public class StatusBar extends SystemUI implements DemoMode, // all notifications protected NotificationStackScrollLayout mStackScroller; - private final NotificationGroupManager mGroupManager; - // handling reordering private final VisualStabilityManager mVisualStabilityManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 777bf3f73480..b56993b5f439 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -44,15 +44,13 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.KeyguardViewController; import com.android.keyguard.ViewMediatorCallback; +import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.settingslib.animation.AppearAnimationUtils; import com.android.systemui.DejankUtils; -import com.android.systemui.SystemUIFactory; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dock.DockManager; -import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.FaceAuthScreenBrightnessController; import com.android.systemui.navigationbar.NavigationModeController; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.SysUiStatsLog; @@ -106,6 +104,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private final NavigationModeController mNavigationModeController; private final NotificationShadeWindowController mNotificationShadeWindowController; private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController; + private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() { @Override public void onFullyShown() { @@ -216,7 +215,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb NotificationShadeWindowController notificationShadeWindowController, KeyguardStateController keyguardStateController, Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController, - NotificationMediaManager notificationMediaManager) { + NotificationMediaManager notificationMediaManager, + KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) { mContext = context; mViewMediatorCallback = callback; mLockPatternUtils = lockPatternUtils; @@ -229,6 +229,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mStatusBarStateController = sysuiStatusBarStateController; mDockManager = dockManager; mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController; + mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory; } @Override @@ -236,9 +237,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb ViewGroup container, NotificationPanelViewController notificationPanelViewController, BiometricUnlockController biometricUnlockController, - DismissCallbackRegistry dismissCallbackRegistry, ViewGroup lockIconContainer, View notificationContainer, - KeyguardBypassController bypassController, FalsingManager falsingManager) { + KeyguardBypassController bypassController) { mStatusBar = statusBar; mContainer = container; mLockIconContainer = lockIconContainer; @@ -246,9 +246,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mLastLockVisible = mLockIconContainer.getVisibility() == View.VISIBLE; } mBiometricUnlockController = biometricUnlockController; - mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext, - mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry, - mExpansionCallback, mKeyguardStateController, falsingManager, bypassController); + mBouncer = mKeyguardBouncerComponentFactory + .build(container, mExpansionCallback) + .createKeyguardBouncer(); mNotificationPanelViewController = notificationPanelViewController; notificationPanelViewController.addExpansionListener(this); mBypassController = bypassController; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index de11c9023200..f80656706f37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -66,10 +66,10 @@ import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -96,7 +96,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final NotificationEntryManager mEntryManager; private final NotifPipeline mNotifPipeline; - private final NotifCollection mNotifCollection; private final HeadsUpManagerPhone mHeadsUpManager; private final ActivityStarter mActivityStarter; private final NotificationClickNotifier mClickNotifier; @@ -107,7 +106,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final BubbleController mBubbleController; private final Lazy<AssistManager> mAssistManagerLazy; private final NotificationRemoteInputManager mRemoteInputManager; - private final NotificationGroupManager mGroupManager; + private final GroupMembershipManager mGroupMembershipManager; private final NotificationLockscreenUserManager mLockscreenUserManager; private final ShadeController mShadeController; private final KeyguardStateController mKeyguardStateController; @@ -135,7 +134,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit Executor uiBgExecutor, NotificationEntryManager entryManager, NotifPipeline notifPipeline, - NotifCollection notifCollection, HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter, NotificationClickNotifier clickNotifier, @@ -146,7 +144,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit BubbleController bubbleController, Lazy<AssistManager> assistManagerLazy, NotificationRemoteInputManager remoteInputManager, - NotificationGroupManager groupManager, + GroupMembershipManager groupMembershipManager, NotificationLockscreenUserManager lockscreenUserManager, ShadeController shadeController, KeyguardStateController keyguardStateController, @@ -170,7 +168,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mUiBgExecutor = uiBgExecutor; mEntryManager = entryManager; mNotifPipeline = notifPipeline; - mNotifCollection = notifCollection; mHeadsUpManager = headsUpManager; mActivityStarter = activityStarter; mClickNotifier = clickNotifier; @@ -181,7 +178,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mBubbleController = bubbleController; mAssistManagerLazy = assistManagerLazy; mRemoteInputManager = remoteInputManager; - mGroupManager = groupManager; + mGroupMembershipManager = groupMembershipManager; mLockscreenUserManager = lockscreenUserManager; mShadeController = shadeController; mKeyguardStateController = keyguardStateController; @@ -228,8 +225,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) { mLogger.logStartingActivityFromClick(sbn.getKey()); + final NotificationEntry entry = row.getEntry(); RemoteInputController controller = mRemoteInputManager.getController(); - if (controller.isRemoteInputActive(row.getEntry()) + if (controller.isRemoteInputActive(entry) && !TextUtils.isEmpty(row.getActiveRemoteInputText())) { // We have an active remote input typed and the user clicked on the notification. // this was probably unintentional, so we're closing the edit text instead. @@ -240,7 +238,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit final PendingIntent intent = notification.contentIntent != null ? notification.contentIntent : notification.fullScreenIntent; - final boolean isBubble = row.getEntry().isBubble(); + final boolean isBubble = entry.isBubble(); // This code path is now executed for notification without a contentIntent. // The only valid case is Bubble notifications. Guard against other cases @@ -260,7 +258,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mLockscreenUserManager.getCurrentUserId()); ActivityStarter.OnDismissAction postKeyguardAction = () -> handleNotificationClickAfterKeyguardDismissed( - sbn, row, controller, intent, + entry, row, controller, intent, isActivityIntent, wasOccluded, showOverLockscreen); if (showOverLockscreen) { mIsCollapsingToShowActivityOverLockscreen = true; @@ -272,27 +270,27 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } private boolean handleNotificationClickAfterKeyguardDismissed( - StatusBarNotification sbn, + NotificationEntry entry, ExpandableNotificationRow row, RemoteInputController controller, PendingIntent intent, boolean isActivityIntent, boolean wasOccluded, boolean showOverLockscreen) { - mLogger.logHandleClickAfterKeyguardDismissed(sbn.getKey()); + mLogger.logHandleClickAfterKeyguardDismissed(entry.getKey()); // TODO: Some of this code may be able to move to NotificationEntryManager. removeHUN(row); NotificationEntry parentToCancel = null; - if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) { - NotificationEntry summarySbn = mGroupManager.getLogicalGroupSummary(sbn); + if (shouldAutoCancel(entry.getSbn()) && mGroupMembershipManager.isOnlyChildInGroup(entry)) { + NotificationEntry summarySbn = mGroupMembershipManager.getLogicalGroupSummary(entry); if (shouldAutoCancel(summarySbn.getSbn())) { parentToCancel = summarySbn; } } final NotificationEntry parentToCancelFinal = parentToCancel; final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed( - sbn, row, controller, intent, + entry, row, controller, intent, isActivityIntent, wasOccluded, parentToCancelFinal); if (showOverLockscreen) { @@ -309,16 +307,16 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } private void handleNotificationClickAfterPanelCollapsed( - StatusBarNotification sbn, + NotificationEntry entry, ExpandableNotificationRow row, RemoteInputController controller, PendingIntent intent, boolean isActivityIntent, boolean wasOccluded, NotificationEntry parentToCancelFinal) { - mLogger.logHandleClickAfterPanelCollapsed(sbn.getKey()); + String notificationKey = entry.getKey(); + mLogger.logHandleClickAfterPanelCollapsed(notificationKey); - String notificationKey = sbn.getKey(); try { // The intent we are sending is for the application, which // won't have permission to immediately start an activity after @@ -346,7 +344,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } } Intent fillInIntent = null; - NotificationEntry entry = row.getEntry(); CharSequence remoteInputText = null; if (!TextUtils.isEmpty(entry.remoteInputText)) { remoteInputText = entry.remoteInputText; @@ -385,7 +382,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit // necessary in the new pipeline due to group pruning in ShadeListBuilder. removeNotification(parentToCancelFinal); } - if (shouldAutoCancel(sbn) + if (shouldAutoCancel(entry.getSbn()) || mRemoteInputManager.isNotificationKeptForRemoteInputHistory( notificationKey)) { // Automatically remove all notifications that we may have kept around longer @@ -605,7 +602,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final Executor mUiBgExecutor; private final NotificationEntryManager mEntryManager; private final NotifPipeline mNotifPipeline; - private final NotifCollection mNotifCollection; private final HeadsUpManagerPhone mHeadsUpManager; private final ActivityStarter mActivityStarter; private final NotificationClickNotifier mClickNotifier; @@ -616,7 +612,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final BubbleController mBubbleController; private final Lazy<AssistManager> mAssistManagerLazy; private final NotificationRemoteInputManager mRemoteInputManager; - private final NotificationGroupManager mGroupManager; + private final GroupMembershipManager mGroupMembershipManager; private final NotificationLockscreenUserManager mLockscreenUserManager; private final ShadeController mShadeController; private final KeyguardStateController mKeyguardStateController; @@ -643,7 +639,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit @UiBackground Executor uiBgExecutor, NotificationEntryManager entryManager, NotifPipeline notifPipeline, - NotifCollection notifCollection, HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter, NotificationClickNotifier clickNotifier, @@ -654,7 +649,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit BubbleController bubbleController, Lazy<AssistManager> assistManagerLazy, NotificationRemoteInputManager remoteInputManager, - NotificationGroupManager groupManager, + GroupMembershipManager groupMembershipManager, NotificationLockscreenUserManager lockscreenUserManager, ShadeController shadeController, KeyguardStateController keyguardStateController, @@ -674,7 +669,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mUiBgExecutor = uiBgExecutor; mEntryManager = entryManager; mNotifPipeline = notifPipeline; - mNotifCollection = notifCollection; mHeadsUpManager = headsUpManager; mActivityStarter = activityStarter; mClickNotifier = clickNotifier; @@ -685,7 +679,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mBubbleController = bubbleController; mAssistManagerLazy = assistManagerLazy; mRemoteInputManager = remoteInputManager; - mGroupManager = groupManager; + mGroupMembershipManager = groupMembershipManager; mLockscreenUserManager = lockscreenUserManager; mShadeController = shadeController; mKeyguardStateController = keyguardStateController; @@ -731,7 +725,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mUiBgExecutor, mEntryManager, mNotifPipeline, - mNotifCollection, mHeadsUpManager, mActivityStarter, mClickNotifier, @@ -742,7 +735,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mBubbleController, mAssistManagerLazy, mRemoteInputManager, - mGroupManager, + mGroupMembershipManager, mLockscreenUserManager, mShadeController, mKeyguardStateController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java index 8a8942975d2e..36519ac0d808 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java @@ -45,6 +45,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationRemoteInputManager.Callback; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -65,7 +66,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final ShadeController mShadeController; private final ActivityIntentHelper mActivityIntentHelper; - private final NotificationGroupManager mGroupManager; + private final GroupExpansionManager mGroupExpansionManager; private View mPendingWorkRemoteInputView; private View mPendingRemoteInputView; private KeyguardManager mKeyguardManager; @@ -78,12 +79,15 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, /** */ @Inject - public StatusBarRemoteInputCallback(Context context, NotificationGroupManager groupManager, + public StatusBarRemoteInputCallback( + Context context, + GroupExpansionManager groupExpansionManager, NotificationLockscreenUserManager notificationLockscreenUserManager, KeyguardStateController keyguardStateController, StatusBarStateController statusBarStateController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, - ActivityStarter activityStarter, ShadeController shadeController, + ActivityStarter activityStarter, + ShadeController shadeController, CommandQueue commandQueue, ActionClickLogger clickLogger) { mContext = context; @@ -101,7 +105,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, mCommandQueue.addCallback(this); mActionClickLogger = clickLogger; mActivityIntentHelper = new ActivityIntentHelper(mContext); - mGroupManager = groupManager; + mGroupExpansionManager = groupExpansionManager; } @Override @@ -182,7 +186,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, } else { if (row.isChildInGroup() && !row.areChildrenExpanded()) { // The group isn't expanded, let's make sure it's visible! - mGroupManager.toggleGroupExpansion(row.getEntry().getSbn()); + mGroupExpansionManager.toggleGroupExpansion(row.getEntry()); } row.setUserExpanded(true); row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index 72067d376f7c..16c3dc460a9c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -80,7 +80,6 @@ import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.LightsOutNotifController; import com.android.systemui.statusbar.phone.LockscreenLockIconController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; import com.android.systemui.statusbar.phone.ScrimController; @@ -158,7 +157,6 @@ public interface StatusBarPhoneModule { SysuiStatusBarStateController statusBarStateController, VibratorHelper vibratorHelper, BubbleController bubbleController, - NotificationGroupManager groupManager, VisualStabilityManager visualStabilityManager, DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, @@ -238,7 +236,6 @@ public interface StatusBarPhoneModule { statusBarStateController, vibratorHelper, bubbleController, - groupManager, visualStabilityManager, deviceProvisionedController, navigationBarController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java index 9b4e16525df2..485b1b109eb4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java @@ -15,8 +15,6 @@ package com.android.systemui.statusbar.policy; import android.app.ActivityManager; -import android.content.ContentResolver; -import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; @@ -30,6 +28,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.settings.CurrentUserTracker; +import com.android.systemui.util.settings.GlobalSettings; +import com.android.systemui.util.settings.SecureSettings; import java.util.ArrayList; @@ -43,8 +43,8 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen protected static final String TAG = DeviceProvisionedControllerImpl.class.getSimpleName(); protected final ArrayList<DeviceProvisionedListener> mListeners = new ArrayList<>(); - private final ContentResolver mContentResolver; - private final Context mContext; + private final GlobalSettings mGlobalSettings; + private final SecureSettings mSecureSettings; private final Uri mDeviceProvisionedUri; private final Uri mUserSetupUri; protected final ContentObserver mSettingsObserver; @@ -52,13 +52,14 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen /** */ @Inject - public DeviceProvisionedControllerImpl(Context context, @Main Handler mainHandler, - BroadcastDispatcher broadcastDispatcher) { + public DeviceProvisionedControllerImpl(@Main Handler mainHandler, + BroadcastDispatcher broadcastDispatcher, GlobalSettings globalSettings, + SecureSettings secureSettings) { super(broadcastDispatcher); - mContext = context; - mContentResolver = context.getContentResolver(); - mDeviceProvisionedUri = Global.getUriFor(Global.DEVICE_PROVISIONED); - mUserSetupUri = Secure.getUriFor(Secure.USER_SETUP_COMPLETE); + mGlobalSettings = globalSettings; + mSecureSettings = secureSettings; + mDeviceProvisionedUri = mGlobalSettings.getUriFor(Global.DEVICE_PROVISIONED); + mUserSetupUri = mSecureSettings.getUriFor(Secure.USER_SETUP_COMPLETE); mSettingsObserver = new ContentObserver(mainHandler) { @Override public void onChange(boolean selfChange, Uri uri, int flags) { @@ -74,13 +75,12 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen @Override public boolean isDeviceProvisioned() { - return Global.getInt(mContentResolver, Global.DEVICE_PROVISIONED, 0) != 0; + return mGlobalSettings.getInt(Global.DEVICE_PROVISIONED, 0) != 0; } @Override public boolean isUserSetup(int currentUser) { - return Secure.getIntForUser(mContentResolver, Secure.USER_SETUP_COMPLETE, 0, currentUser) - != 0; + return mSecureSettings.getIntForUser(Secure.USER_SETUP_COMPLETE, 0, currentUser) != 0; } @Override @@ -107,24 +107,24 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen } protected void startListening(int user) { - mContentResolver.registerContentObserver(mDeviceProvisionedUri, true, + mGlobalSettings.registerContentObserverForUser(mDeviceProvisionedUri, true, mSettingsObserver, 0); - mContentResolver.registerContentObserver(mUserSetupUri, true, + mSecureSettings.registerContentObserverForUser(mUserSetupUri, true, mSettingsObserver, user); startTracking(); } protected void stopListening() { stopTracking(); - mContentResolver.unregisterContentObserver(mSettingsObserver); + mGlobalSettings.unregisterContentObserver(mSettingsObserver); } @Override public void onUserSwitched(int newUserId) { - mContentResolver.unregisterContentObserver(mSettingsObserver); - mContentResolver.registerContentObserver(mDeviceProvisionedUri, true, + mGlobalSettings.unregisterContentObserver(mSettingsObserver); + mGlobalSettings.registerContentObserverForUser(mDeviceProvisionedUri, true, mSettingsObserver, 0); - mContentResolver.registerContentObserver(mUserSetupUri, true, + mSecureSettings.registerContentObserverForUser(mUserSetupUri, true, mSettingsObserver, newUserId); notifyUserChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index f9ac760a3367..17fcb1dd6f1a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -206,7 +206,7 @@ public class UserSwitcherController implements Dumpable { @Override protected ArrayList<UserRecord> doInBackground(SparseArray<Bitmap>... params) { final SparseArray<Bitmap> bitmaps = params[0]; - List<UserInfo> infos = mUserManager.getUsers(true); + List<UserInfo> infos = mUserManager.getAliveUsers(); if (infos == null) { return null; } 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 000000000000..914105fdc4c4 --- /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/tuner/dagger/TunerModule.java b/packages/SystemUI/src/com/android/systemui/tuner/dagger/TunerModule.java new file mode 100644 index 000000000000..faf7b842f3b2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tuner/dagger/TunerModule.java @@ -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. + */ + +package com.android.systemui.tuner.dagger; + +import com.android.systemui.tuner.TunerService; +import com.android.systemui.tuner.TunerServiceImpl; + +import dagger.Binds; +import dagger.Module; + +/** 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 3577bc05d1c4..bef05ebb724e 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 @@ import dagger.Subcomponent; @Subcomponent(modules = { DefaultComponentBinder.class, DependencyProvider.class, - DependencyBinder.class, SystemUIBinder.class, SystemUIModule.class, TvSystemUIModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java index e7c10f1697f5..d727bfbdf48a 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java @@ -47,11 +47,11 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.phone.DozeServiceHost; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowControllerImpl; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.ShadeControllerImpl; @@ -136,7 +136,7 @@ public abstract class TvSystemUIModule { Context context, StatusBarStateController statusBarStateController, KeyguardBypassController bypassController, - NotificationGroupManager groupManager, + NotificationGroupManagerLegacy groupManager, ConfigurationController configurationController) { return new HeadsUpManagerPhone(context, statusBarStateController, bypassController, groupManager, configurationController); 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 000000000000..5946af383b0f --- /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 index 628c808aa12b..b9b20c73c5d5 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 com.android.systemui.dagger.qualifiers.UiBackground; import java.util.concurrent.Executor; import java.util.concurrent.Executors; -import dagger.Binds; import dagger.Module; import dagger.Provides; @@ -39,7 +37,7 @@ import dagger.Provides; * 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 @@ public abstract class ConcurrencyModule { return thread.getLooper(); } - /** Main Looper */ - @Provides - @Main - public static Looper provideMainLooper() { - return Looper.getMainLooper(); - } - /** * Background Handler. * @@ -81,17 +72,6 @@ public abstract class ConcurrencyModule { } /** - * 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 @@ public abstract class ConcurrencyModule { } /** - * 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 abstract class ConcurrencyModule { 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/util/dagger/UtilModule.java b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java new file mode 100644 index 000000000000..cdfa1457f4a5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java @@ -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. + */ + +package com.android.systemui.util.dagger; + +import com.android.systemui.util.RingerModeTracker; +import com.android.systemui.util.RingerModeTrackerImpl; + +import dagger.Binds; +import dagger.Module; + +/** 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/util/settings/SettingsProxy.java b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java index 5c37f797b678..5aaf7f680d5c 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java +++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java @@ -67,7 +67,35 @@ public interface SettingsProxy { * Implicitly calls {@link #getUriFor(String)} on the passed in name. */ default void registerContentObserver(String name, ContentObserver settingsObserver) { - registerContentObserverForUser(name, settingsObserver, getUserId()); + registerContentObserver(getUriFor(name), settingsObserver); + } + + /** + * Convenience wrapper around + * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.' + */ + default void registerContentObserver(Uri uri, ContentObserver settingsObserver) { + registerContentObserverForUser(uri, settingsObserver, getUserId()); + } + + /** + * Convenience wrapper around + * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.' + * + * Implicitly calls {@link #getUriFor(String)} on the passed in name. + */ + default void registerContentObserver(String name, boolean notifyForDescendents, + ContentObserver settingsObserver) { + registerContentObserver(getUriFor(name), notifyForDescendents, settingsObserver); + } + + /** + * Convenience wrapper around + * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.' + */ + default void registerContentObserver(Uri uri, boolean notifyForDescendents, + ContentObserver settingsObserver) { + registerContentObserverForUser(uri, notifyForDescendents, settingsObserver, getUserId()); } /** @@ -78,8 +106,42 @@ public interface SettingsProxy { */ default void registerContentObserverForUser( String name, ContentObserver settingsObserver, int userHandle) { + registerContentObserverForUser( + getUriFor(name), settingsObserver, userHandle); + } + + /** + * Convenience wrapper around + * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)} + */ + default void registerContentObserverForUser( + Uri uri, ContentObserver settingsObserver, int userHandle) { + registerContentObserverForUser( + uri, false, settingsObserver, userHandle); + } + + /** + * Convenience wrapper around + * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)} + * + * Implicitly calls {@link #getUriFor(String)} on the passed in name. + */ + default void registerContentObserverForUser( + String name, boolean notifyForDescendents, ContentObserver settingsObserver, + int userHandle) { + registerContentObserverForUser( + getUriFor(name), notifyForDescendents, settingsObserver, userHandle); + } + + /** + * Convenience wrapper around + * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)} + */ + default void registerContentObserverForUser( + Uri uri, boolean notifyForDescendents, ContentObserver settingsObserver, + int userHandle) { getContentResolver().registerContentObserver( - getUriFor(name), false, settingsObserver, userHandle); + uri, notifyForDescendents, settingsObserver, userHandle); } /** See {@link ContentResolver#unregisterContentObserver(ContentObserver)}. */ diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 51ad30ebcac6..78f83d3c09b4 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.Resources; 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.View.AccessibilityDelegate; 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 @@ import java.util.List; * 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 @@ public class VolumeDialogImpl implements VolumeDialog, 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 @@ public class VolumeDialogImpl implements VolumeDialog, 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 @@ public class VolumeDialogImpl implements VolumeDialog, 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 @@ public class VolumeDialogImpl implements VolumeDialog, .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 @@ public class VolumeDialogImpl implements VolumeDialog, 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 @@ public class VolumeDialogImpl implements VolumeDialog, 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/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java new file mode 100644 index 000000000000..1ef4c169b786 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java @@ -0,0 +1,32 @@ +/* + * 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.volume.dagger; + +import com.android.systemui.volume.VolumeComponent; +import com.android.systemui.volume.VolumeDialogComponent; + +import dagger.Binds; +import dagger.Module; + + +/** Dagger Module for code in the volume package. */ +@Module +public interface VolumeModule { + /** */ + @Binds + VolumeComponent provideVolumeComponent(VolumeDialogComponent volumeDialogComponent); +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index a7808ad54d63..f65c2c91c50a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -77,13 +77,13 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.LockscreenLockIconController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowControllerImpl; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; import com.android.systemui.statusbar.phone.ShadeController; @@ -118,7 +118,7 @@ public class BubbleControllerTest extends SysuiTestCase { @Mock private NotificationEntryManager mNotificationEntryManager; @Mock - private NotificationGroupManager mNotificationGroupManager; + private NotificationGroupManagerLegacy mNotificationGroupManager; @Mock private WindowManager mWindowManager; @Mock diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java index 4936360756fd..dd191e9cd328 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -75,6 +75,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; @@ -82,7 +83,6 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfC import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.LockscreenLockIconController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowControllerImpl; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; import com.android.systemui.statusbar.phone.ShadeController; @@ -116,7 +116,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { @Mock private NotificationEntryManager mNotificationEntryManager; @Mock - private NotificationGroupManager mNotificationGroupManager; + private NotificationGroupManagerLegacy mNotificationGroupManager; @Mock private BubbleController.NotifCallback mNotifCallback; @Mock diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java index 51ca2a4e5966..58b27f24a1d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java @@ -30,8 +30,8 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ZenModeController; @@ -52,7 +52,7 @@ public class TestableBubbleController extends BubbleController { NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, NotificationLockscreenUserManager lockscreenUserManager, - NotificationGroupManager groupManager, + NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager, NotifPipeline notifPipeline, FeatureFlags featureFlags, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index d2bf483a6bd6..d041ee047ae0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -45,6 +45,7 @@ import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.inflation.LowPriorityInflationHelper; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -53,7 +54,6 @@ import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.google.android.collect.Lists; @@ -76,7 +76,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { // Dependency mocks: @Mock private NotificationEntryManager mEntryManager; @Mock private NotificationLockscreenUserManager mLockscreenUserManager; - @Mock private NotificationGroupManager mGroupManager; + @Mock private NotificationGroupManagerLegacy mGroupManager; @Mock private VisualStabilityManager mVisualStabilityManager; private TestableLooper mTestableLooper; @@ -95,7 +95,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager); mDependency.injectTestDependency(NotificationLockscreenUserManager.class, mLockscreenUserManager); - mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager); + mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, mGroupManager); mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager); when(mVisualStabilityManager.areGroupChangesAllowed()).thenReturn(true); when(mVisualStabilityManager.isReorderingAllowed()).thenReturn(true); @@ -136,11 +136,11 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { Lists.newArrayList(entry0, entry1, entry2)); // Set up group manager to report that they should be bundled now. - when(mGroupManager.isChildInGroupWithSummary(entry0.getSbn())).thenReturn(false); - when(mGroupManager.isChildInGroupWithSummary(entry1.getSbn())).thenReturn(true); - when(mGroupManager.isChildInGroupWithSummary(entry2.getSbn())).thenReturn(true); - when(mGroupManager.getGroupSummary(entry1.getSbn())).thenReturn(entry0); - when(mGroupManager.getGroupSummary(entry2.getSbn())).thenReturn(entry0); + when(mGroupManager.isChildInGroup(entry0)).thenReturn(false); + when(mGroupManager.isChildInGroup(entry1)).thenReturn(true); + when(mGroupManager.isChildInGroup(entry2)).thenReturn(true); + when(mGroupManager.getGroupSummary(entry1)).thenReturn(entry0); + when(mGroupManager.getGroupSummary(entry2)).thenReturn(entry0); // Run updateNotifications - the view hierarchy should be reorganized. mViewHierarchyManager.updateNotificationViews(); @@ -165,9 +165,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { Lists.newArrayList(entry0, entry1, entry2)); // Set up group manager to report that they should not be bundled now. - when(mGroupManager.isChildInGroupWithSummary(entry0.getSbn())).thenReturn(false); - when(mGroupManager.isChildInGroupWithSummary(entry1.getSbn())).thenReturn(false); - when(mGroupManager.isChildInGroupWithSummary(entry2.getSbn())).thenReturn(false); + when(mGroupManager.isChildInGroup(entry0)).thenReturn(false); + when(mGroupManager.isChildInGroup(entry1)).thenReturn(false); + when(mGroupManager.isChildInGroup(entry2)).thenReturn(false); // Run updateNotifications - the view hierarchy should be reorganized. mViewHierarchyManager.updateNotificationViews(); @@ -194,8 +194,8 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { Lists.newArrayList(entry0, entry1)); // Set up group manager to report a suppressed summary now. - when(mGroupManager.isChildInGroupWithSummary(entry0.getSbn())).thenReturn(false); - when(mGroupManager.isChildInGroupWithSummary(entry1.getSbn())).thenReturn(false); + when(mGroupManager.isChildInGroup(entry0)).thenReturn(false); + when(mGroupManager.isChildInGroup(entry1)).thenReturn(false); when(mGroupManager.isSummaryOfSuppressedGroup(entry0.getSbn())).thenReturn(true); // Run updateNotifications - the view hierarchy should be reorganized. diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index fc0201ad82f0..3e1616c9fa7b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -75,13 +75,13 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationEntryManagerInflationTest; import com.android.systemui.statusbar.notification.row.RowInflaterTask; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.leak.LeakDetector; @@ -119,7 +119,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Mock private NotificationRemoveInterceptor mRemoveInterceptor; @Mock private HeadsUpManager mHeadsUpManager; @Mock private RankingMap mRankingMap; - @Mock private NotificationGroupManager mGroupManager; + @Mock private NotificationGroupManagerLegacy mGroupManager; @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private DeviceProvisionedController mDeviceProvisionedController; @Mock private RowInflaterTask mAsyncInflationTask; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java index 5a81d36ea744..dfe006dfd4fe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java @@ -48,10 +48,10 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; import org.junit.After; @@ -109,8 +109,8 @@ public class NotificationFilterTest extends SysuiTestCase { eq(UID_ALLOW_DURING_SETUP))) .thenReturn(PackageManager.PERMISSION_GRANTED); mDependency.injectTestDependency(ForegroundServiceController.class, mFsc); - mDependency.injectTestDependency(NotificationGroupManager.class, - new NotificationGroupManager( + mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, + new NotificationGroupManagerLegacy( mock(StatusBarStateController.class), () -> mock(PeopleNotificationIdentifier.class))); mDependency.injectMockDependency(ShadeController.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java index 386c866cdd03..14877eec9a83 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java @@ -37,8 +37,8 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import org.junit.Before; import org.junit.Test; @@ -48,12 +48,13 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; @SmallTest @RunWith(AndroidTestingRunner.class) public class HighPriorityProviderTest extends SysuiTestCase { @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier; - @Mock private NotificationGroupManager mGroupManager; + @Mock private GroupMembershipManager mGroupMembershipManager; private HighPriorityProvider mHighPriorityProvider; @Before @@ -61,7 +62,7 @@ public class HighPriorityProviderTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mHighPriorityProvider = new HighPriorityProvider( mPeopleNotificationIdentifier, - mGroupManager); + mGroupMembershipManager); } @Test @@ -71,7 +72,7 @@ public class HighPriorityProviderTest extends SysuiTestCase { .setImportance(IMPORTANCE_HIGH) .build(); when(mPeopleNotificationIdentifier - .getPeopleNotificationType(entry.getSbn(), entry.getRanking())) + .getPeopleNotificationType(entry)) .thenReturn(TYPE_NON_PERSON); // THEN it has high priority @@ -88,7 +89,7 @@ public class HighPriorityProviderTest extends SysuiTestCase { .setImportance(IMPORTANCE_LOW) .build(); when(mPeopleNotificationIdentifier - .getPeopleNotificationType(entry.getSbn(), entry.getRanking())) + .getPeopleNotificationType(entry)) .thenReturn(TYPE_PERSON); // THEN it has high priority @@ -105,7 +106,7 @@ public class HighPriorityProviderTest extends SysuiTestCase { .setNotification(notification) .build(); when(mPeopleNotificationIdentifier - .getPeopleNotificationType(entry.getSbn(), entry.getRanking())) + .getPeopleNotificationType(entry)) .thenReturn(TYPE_NON_PERSON); // THEN it has high priority @@ -123,7 +124,7 @@ public class HighPriorityProviderTest extends SysuiTestCase { .setImportance(IMPORTANCE_LOW) .build(); when(mPeopleNotificationIdentifier - .getPeopleNotificationType(entry.getSbn(), entry.getRanking())) + .getPeopleNotificationType(entry)) .thenReturn(TYPE_NON_PERSON); // THEN it has high priority @@ -141,7 +142,7 @@ public class HighPriorityProviderTest extends SysuiTestCase { .setImportance(IMPORTANCE_MIN) .build(); when(mPeopleNotificationIdentifier - .getPeopleNotificationType(entry.getSbn(), entry.getRanking())) + .getPeopleNotificationType(entry)) .thenReturn(TYPE_NON_PERSON); // THEN it does NOT have high priority @@ -165,7 +166,7 @@ public class HighPriorityProviderTest extends SysuiTestCase { .setChannel(channel) .build(); when(mPeopleNotificationIdentifier - .getPeopleNotificationType(entry.getSbn(), entry.getRanking())) + .getPeopleNotificationType(entry)) .thenReturn(TYPE_PERSON); // THEN it does NOT have high priority @@ -173,13 +174,13 @@ public class HighPriorityProviderTest extends SysuiTestCase { } @Test - public void testIsHighPriority_checkChildrenToCalculatePriority() { + public void testIsHighPriority_checkChildrenToCalculatePriority_legacy() { // GIVEN: a summary with low priority has a highPriorityChild and a lowPriorityChild final NotificationEntry summary = createNotifEntry(false); final NotificationEntry lowPriorityChild = createNotifEntry(false); final NotificationEntry highPriorityChild = createNotifEntry(true); - when(mGroupManager.isGroupSummary(summary.getSbn())).thenReturn(true); - when(mGroupManager.getChildren(summary.getSbn())).thenReturn( + when(mGroupMembershipManager.isGroupSummary(summary)).thenReturn(true); + when(mGroupMembershipManager.getChildren(summary)).thenReturn( new ArrayList<>(Arrays.asList(lowPriorityChild, highPriorityChild))); // THEN the summary is high priority since it has a high priority child @@ -210,16 +211,20 @@ public class HighPriorityProviderTest extends SysuiTestCase { } @Test - public void testIsHighPriority_checkChildrenToCalculatePriorityOf() { + public void testIsHighPriority_checkChildrenToCalculatePriority() { // GIVEN: - // GroupEntry = parentEntry, summary = lowPrioritySummary + // parent with summary = lowPrioritySummary // NotificationEntry = lowPriorityChild // NotificationEntry = highPriorityChild + final NotificationEntry lowPrioritySummary = createNotifEntry(false); final GroupEntry parentEntry = new GroupEntryBuilder() - .setSummary(createNotifEntry(false)) - .addChild(createNotifEntry(false)) - .addChild(createNotifEntry(true)) + .setSummary(lowPrioritySummary) .build(); + when(mGroupMembershipManager.getChildren(parentEntry)).thenReturn( + new ArrayList<>( + List.of( + createNotifEntry(false), + createNotifEntry(true)))); // THEN the GroupEntry parentEntry is high priority since it has a high priority child assertTrue(mHighPriorityProvider.isHighPriority(parentEntry)); @@ -228,13 +233,15 @@ public class HighPriorityProviderTest extends SysuiTestCase { @Test public void testIsHighPriority_childEntryRankingUpdated() { // GIVEN: - // GroupEntry = parentEntry, summary = lowPrioritySummary + // parent with summary = lowPrioritySummary // NotificationEntry = lowPriorityChild - final NotificationEntry lowPriorityChild = createNotifEntry(false); + final NotificationEntry lowPrioritySummary = createNotifEntry(false); final GroupEntry parentEntry = new GroupEntryBuilder() - .setSummary(createNotifEntry(false)) - .addChild(lowPriorityChild) + .setSummary(lowPrioritySummary) .build(); + final NotificationEntry lowPriorityChild = createNotifEntry(false); + when(mGroupMembershipManager.getChildren(parentEntry)).thenReturn( + new ArrayList<>(List.of(lowPriorityChild))); // WHEN the child entry ranking changes to high priority lowPriorityChild.setRanking( @@ -243,9 +250,8 @@ public class HighPriorityProviderTest extends SysuiTestCase { .setImportance(IMPORTANCE_HIGH) .build()); - // THEN the parent entry's high priority value is updated - but not the parent's summary + // THEN the parent entry's high priority value is updated assertTrue(mHighPriorityProvider.isHighPriority(parentEntry)); - assertFalse(mHighPriorityProvider.isHighPriority(parentEntry.getSummary())); } private NotificationEntry createNotifEntry(boolean highPriority) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt index 82a7774b4d82..c832fe481f74 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt @@ -40,7 +40,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT -import com.android.systemui.statusbar.phone.NotificationGroupManager +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy import com.android.systemui.statusbar.policy.HeadsUpManager import com.google.common.truth.Truth.assertThat import dagger.Lazy @@ -71,14 +71,14 @@ class NotificationRankingManagerTest : SysuiTestCase() { notificationFilter = mock(NotificationFilter::class.java) rankingManager = TestableNotificationRankingManager( lazyMedia, - mock(NotificationGroupManager::class.java), + mock(NotificationGroupManagerLegacy::class.java), mock(HeadsUpManager::class.java), notificationFilter, mock(NotificationEntryManagerLogger::class.java), sectionsManager, personNotificationIdentifier, HighPriorityProvider(personNotificationIdentifier, - mock(NotificationGroupManager::class.java)) + mock(NotificationGroupManagerLegacy::class.java)) ) } @@ -174,7 +174,7 @@ class NotificationRankingManagerTest : SysuiTestCase() { .setOverrideGroupKey("") .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking)) + whenever(personNotificationIdentifier.getPeopleNotificationType(a)) .thenReturn(TYPE_IMPORTANT_PERSON) val bN = Notification.Builder(mContext, "test") @@ -194,7 +194,7 @@ class NotificationRankingManagerTest : SysuiTestCase() { whenever(it.isHeadsUp).thenReturn(true) } - whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking)) + whenever(personNotificationIdentifier.getPeopleNotificationType(a)) .thenReturn(TYPE_PERSON) assertEquals(listOf(b, a), rankingManager.updateRanking(null, listOf(a, b), "test")) @@ -216,7 +216,7 @@ class NotificationRankingManagerTest : SysuiTestCase() { .setUser(mContext.user) .setOverrideGroupKey("") .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking)) + whenever(personNotificationIdentifier.getPeopleNotificationType(a)) .thenReturn(TYPE_PERSON) val bN = Notification.Builder(mContext, "test") @@ -232,7 +232,7 @@ class NotificationRankingManagerTest : SysuiTestCase() { .setUser(mContext.user) .setOverrideGroupKey("") .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(b.sbn, b.ranking)) + whenever(personNotificationIdentifier.getPeopleNotificationType(b)) .thenReturn(TYPE_IMPORTANT_PERSON) whenever(personNotificationIdentifier.compareTo(TYPE_PERSON, TYPE_IMPORTANT_PERSON)) @@ -261,7 +261,7 @@ class NotificationRankingManagerTest : SysuiTestCase() { .setUser(mContext.user) .setOverrideGroupKey("") .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking)) + whenever(personNotificationIdentifier.getPeopleNotificationType(a)) .thenReturn(TYPE_PERSON) val bN = Notification.Builder(mContext, "test") @@ -277,7 +277,7 @@ class NotificationRankingManagerTest : SysuiTestCase() { .setUser(mContext.user) .setOverrideGroupKey("") .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(b.sbn, b.ranking)) + whenever(personNotificationIdentifier.getPeopleNotificationType(b)) .thenReturn(TYPE_FULL_PERSON) whenever(personNotificationIdentifier.compareTo(TYPE_PERSON, TYPE_FULL_PERSON)) @@ -400,7 +400,7 @@ class NotificationRankingManagerTest : SysuiTestCase() { .setUser(mContext.user) .setOverrideGroupKey("") .build() - whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking)) + whenever(personNotificationIdentifier.getPeopleNotificationType(a)) .thenReturn(TYPE_IMPORTANT_PERSON) assertThat(rankingManager.updateRanking(null, listOf(a, b, c), "test")) @@ -410,7 +410,7 @@ class NotificationRankingManagerTest : SysuiTestCase() { internal class TestableNotificationRankingManager( mediaManager: Lazy<NotificationMediaManager>, - groupManager: NotificationGroupManager, + groupManager: NotificationGroupManagerLegacy, headsUpManager: HeadsUpManager, filter: NotificationFilter, logger: NotificationEntryManagerLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt index c49393d2ed34..09c9bcd967bd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt @@ -84,8 +84,8 @@ class ConversationCoordinatorTest : SysuiTestCase() { @Test fun testInPeopleSection() { - whenever(peopleNotificationIdentifier.getPeopleNotificationType( - entry.sbn, entry.ranking)).thenReturn(TYPE_PERSON) + whenever(peopleNotificationIdentifier.getPeopleNotificationType(entry)) + .thenReturn(TYPE_PERSON) // only put people notifications in this section assertTrue(peopleSectioner.isInSection(entry)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index 7a0a19bd5424..aff8ade6f1ae 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -67,6 +67,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; import com.android.systemui.statusbar.notification.collection.inflation.LowPriorityInflationHelper; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.icon.IconBuilder; import com.android.systemui.statusbar.notification.icon.IconManager; @@ -77,7 +78,6 @@ import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotifica import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.SmartReplyConstants; import com.android.systemui.util.concurrency.FakeExecutor; @@ -130,7 +130,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { @Mock private KeyguardBypassController mKeyguardBypassController; @Mock private StatusBarStateController mStatusBarStateController; - @Mock private NotificationGroupManager mGroupManager; + @Mock private NotificationGroupManagerLegacy mGroupMembershipManager; + @Mock private NotificationGroupManagerLegacy mGroupExpansionManager; @Mock private FeatureFlags mFeatureFlags; @Mock private LeakDetector mLeakDetector; @@ -170,10 +171,10 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { mEntryManager = new NotificationEntryManager( mock(NotificationEntryManagerLogger.class), - mGroupManager, + mGroupMembershipManager, new NotificationRankingManager( () -> mock(NotificationMediaManager.class), - mGroupManager, + mGroupMembershipManager, mHeadsUpManager, mock(NotificationFilter.class), mock(NotificationEntryManagerLogger.class), @@ -228,7 +229,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { new FakeSystemClock(), "FOOBAR", "FOOBAR", mKeyguardBypassController, - mGroupManager, + mGroupMembershipManager, + mGroupExpansionManager, mRowContentBindStage, mock(NotificationLogger.class), mHeadsUpManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index df26c5b15505..b952c056c33d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -57,6 +57,7 @@ import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.notification.ConversationNotificationProcessor; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.icon.IconBuilder; @@ -68,7 +69,6 @@ import com.android.systemui.statusbar.notification.row.NotificationRowContentBin import com.android.systemui.statusbar.phone.ConfigurationControllerImpl; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.SmartReplyConstants; import org.mockito.ArgumentCaptor; @@ -96,7 +96,8 @@ public class NotificationTestHelper { private final Context mContext; private final TestableLooper mTestLooper; private int mId; - private final NotificationGroupManager mGroupManager; + private final NotificationGroupManagerLegacy mGroupMembershipManager; + private final NotificationGroupManagerLegacy mGroupExpansionManager; private ExpandableNotificationRow mRow; private HeadsUpManagerPhone mHeadsUpManager; private final NotifBindPipeline mBindPipeline; @@ -116,13 +117,14 @@ public class NotificationTestHelper { dependency.injectMockDependency(BubbleController.class); dependency.injectMockDependency(NotificationShadeWindowController.class); mStatusBarStateController = mock(StatusBarStateController.class); - mGroupManager = new NotificationGroupManager( + mGroupMembershipManager = new NotificationGroupManagerLegacy( mStatusBarStateController, () -> mock(PeopleNotificationIdentifier.class)); + mGroupExpansionManager = mGroupMembershipManager; mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarStateController, - mock(KeyguardBypassController.class), mock(NotificationGroupManager.class), + mock(KeyguardBypassController.class), mock(NotificationGroupManagerLegacy.class), mock(ConfigurationControllerImpl.class)); - mGroupManager.setHeadsUpManager(mHeadsUpManager); + mGroupMembershipManager.setHeadsUpManager(mHeadsUpManager); mIconManager = new IconManager( mock(CommonNotifCollection.class), mock(LauncherApps.class), @@ -416,7 +418,8 @@ public class NotificationTestHelper { entry.getKey(), mock(ExpansionLogger.class), mock(KeyguardBypassController.class), - mGroupManager, + mGroupMembershipManager, + mGroupExpansionManager, mHeadsUpManager, mBindStage, mock(OnExpandClickListener.class), @@ -434,7 +437,7 @@ public class NotificationTestHelper { // This would be done as part of onAsyncInflationFinished, but we skip large amounts of // the callback chain, so we need to make up for not adding it to the group manager // here. - mGroupManager.onEntryAdded(entry); + mGroupMembershipManager.onEntryAdded(entry); return row; } 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 62b741c1938a..5264458cb9cd 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 @@ -47,9 +47,6 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.ExpandHelper; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.classifier.FalsingManagerFake; -import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; -import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationMediaManager; @@ -72,6 +69,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; @@ -80,8 +78,6 @@ import com.android.systemui.statusbar.notification.row.FooterView; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; 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.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.leak.LeakDetector; @@ -115,7 +111,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private SysuiStatusBarStateController mBarState; @Mock private HeadsUpManagerPhone mHeadsUpManager; @Mock private NotificationBlockingHelperManager mBlockingHelperManager; - @Mock private NotificationGroupManager mGroupManager; + @Mock private NotificationGroupManagerLegacy mGroupMembershipManger; + @Mock private NotificationGroupManagerLegacy mGroupExpansionManager; @Mock private ExpandHelper mExpandHelper; @Mock private EmptyShadeView mEmptyShadeView; @Mock private NotificationRemoteInputManager mRemoteInputManager; @@ -128,6 +125,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private FeatureFlags mFeatureFlags; @Mock private SysuiStatusBarStateController mStatusBarStateController; @Mock private NotificationSwipeHelper mNotificationSwipeHelper; + @Mock NotificationStackScrollLayoutController mStackScrollLayoutController; private NotificationEntryManager mEntryManager; private int mOriginalInterruptionModelSetting; private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake(); @@ -159,10 +157,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mEntryManager = new NotificationEntryManager( mock(NotificationEntryManagerLogger.class), - mock(NotificationGroupManager.class), + mock(NotificationGroupManagerLegacy.class), new NotificationRankingManager( () -> mock(NotificationMediaManager.class), - mGroupManager, + mGroupMembershipManger, mHeadsUpManager, mock(NotificationFilter.class), mock(NotificationEntryManagerLogger.class), @@ -207,15 +205,19 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mock(NotifPipeline.class), mEntryManager, mock(NotifCollection.class), - mUiEventLoggerFake + mUiEventLoggerFake, + mGroupMembershipManger, + mGroupExpansionManager ); mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider, mNotificationSwipeHelper); mStackScroller = spy(mStackScrollerInternal); mStackScroller.setShelfController(notificationShelfController); mStackScroller.setStatusBar(mBar); - mStackScroller.setGroupManager(mGroupManager); mStackScroller.setEmptyShadeView(mEmptyShadeView); + when(mStackScrollLayoutController.getNoticationRoundessManager()) + .thenReturn(mock(NotificationRoundnessManager.class)); + mStackScroller.setController(mStackScrollLayoutController); // Stub out functionality that isn't necessary to test. doNothing().when(mBar) @@ -224,7 +226,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { anyBoolean(), anyBoolean(), anyBoolean()); - doNothing().when(mGroupManager).collapseAllGroups(); + doNothing().when(mGroupExpansionManager).collapseGroups(); doNothing().when(mExpandHelper).cancelImmediately(); doNothing().when(notificationShelf).setAnimationsEnabled(anyBoolean()); } 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 f5d9fa07fa1c..32c682878c28 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 @@ -16,6 +16,9 @@ package com.android.systemui.statusbar.notification.stack; +import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; +import static com.android.systemui.statusbar.StatusBarState.SHADE; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; @@ -45,11 +48,11 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; 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; @@ -62,6 +65,7 @@ import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -114,6 +118,11 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { private StatusBar mStatusBar; @Mock private ScrimController mScrimController; + @Mock + private NotificationGroupManagerLegacy mLegacyGroupManager; + + @Captor + ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor; private NotificationStackScrollLayoutController mController; @@ -143,7 +152,9 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { mResources, mNotificationSwipeHelperBuilder, mStatusBar, - mScrimController + mScrimController, + mLegacyGroupManager, + mLegacyGroupManager ); when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true); @@ -181,32 +192,49 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { } @Test - public void testUpdateEmptyShadeView_notificationsVisible() { + public void testUpdateEmptyShadeView_notificationsVisible_zenHiding() { when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true); mController.attach(mNotificationStackScrollLayout); + verify(mSysuiStatusBarStateController).addCallback( + mStateListenerArgumentCaptor.capture(), anyInt()); + StatusBarStateController.StateListener stateListener = + mStateListenerArgumentCaptor.getValue(); - mController.updateEmptyShadeView(true /* visible */); + setupShowEmptyShadeViewState(stateListener, true); + reset(mNotificationStackScrollLayout); + mController.updateShowEmptyShadeView(); verify(mNotificationStackScrollLayout).updateEmptyShadeView( true /* visible */, + true /* notifVisibleInShade */); + + setupShowEmptyShadeViewState(stateListener, false); reset(mNotificationStackScrollLayout); - mController.updateEmptyShadeView(false /* visible */); + mController.updateShowEmptyShadeView(); verify(mNotificationStackScrollLayout).updateEmptyShadeView( false /* visible */, true /* notifVisibleInShade */); } @Test - public void testUpdateEmptyShadeView_notificationsHidden() { + public void testUpdateEmptyShadeView_notificationsHidden_zenNotHiding() { when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false); mController.attach(mNotificationStackScrollLayout); + verify(mSysuiStatusBarStateController).addCallback( + mStateListenerArgumentCaptor.capture(), anyInt()); + StatusBarStateController.StateListener stateListener = + mStateListenerArgumentCaptor.getValue(); - mController.updateEmptyShadeView(true /* visible */); + setupShowEmptyShadeViewState(stateListener, true); + reset(mNotificationStackScrollLayout); + mController.updateShowEmptyShadeView(); verify(mNotificationStackScrollLayout).updateEmptyShadeView( true /* visible */, false /* notifVisibleInShade */); + + setupShowEmptyShadeViewState(stateListener, false); reset(mNotificationStackScrollLayout); - mController.updateEmptyShadeView(false /* visible */); + mController.updateShowEmptyShadeView(); verify(mNotificationStackScrollLayout).updateEmptyShadeView( false /* visible */, false /* notifVisibleInShade */); @@ -234,15 +262,12 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { public void testOnStatePostChange_verifyIfProfileIsPublic() { when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true); - ArgumentCaptor<StatusBarStateController.StateListener> stateListenerArgumentCaptor = - ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); - mController.attach(mNotificationStackScrollLayout); verify(mSysuiStatusBarStateController).addCallback( - stateListenerArgumentCaptor.capture(), anyInt()); + mStateListenerArgumentCaptor.capture(), anyInt()); StatusBarStateController.StateListener stateListener = - stateListenerArgumentCaptor.getValue(); + mStateListenerArgumentCaptor.getValue(); stateListener.onStatePostChange(); verify(mNotificationStackScrollLayout).updateSensitiveness(false, true); @@ -299,6 +324,20 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { return argThat(new LogMatcher(category, type)); } + private void setupShowEmptyShadeViewState( + StatusBarStateController.StateListener statusBarStateListener, + boolean toShow) { + if (toShow) { + statusBarStateListener.onStateChanged(SHADE); + mController.setQsExpanded(false); + mController.getView().removeAllViews(); + } else { + statusBarStateListener.onStateChanged(KEYGUARD); + mController.setQsExpanded(true); + mController.getView().addContainerView(mock(ExpandableNotificationRow.class)); + } + } + static class LogMatcher implements ArgumentMatcher<LogMaker> { private int mCategory, mType; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index 2239b1b96ac8..57020eb08a7f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java @@ -36,6 +36,7 @@ import com.android.systemui.statusbar.AlertingNotificationManagerTest; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -57,7 +58,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { private HeadsUpManagerPhone mHeadsUpManager; - @Mock private NotificationGroupManager mGroupManager; + @Mock private NotificationGroupManagerLegacy mGroupManager; @Mock private View mNotificationShadeWindowView; @Mock private VisualStabilityManager mVSManager; @Mock private StatusBar mBar; @@ -69,7 +70,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { private final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone { TestableHeadsUpManagerPhone( Context context, - NotificationGroupManager groupManager, + NotificationGroupManagerLegacy groupManager, VisualStabilityManager vsManager, StatusBarStateController statusBarStateController, KeyguardBypassController keyguardBypassController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java index 885dff39f7b3..2ece8be8d332 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java @@ -42,6 +42,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback; import com.android.systemui.statusbar.notification.row.RowContentBindParams; @@ -68,7 +69,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Rule public MockitoRule rule = MockitoJUnit.rule(); private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; - private NotificationGroupManager mGroupManager; + private NotificationGroupManagerLegacy mGroupManager; private HeadsUpManager mHeadsUpManager; @Mock private NotificationEntryManager mNotificationEntryManager; @Mock private RowContentBindStage mBindStage; @@ -88,10 +89,10 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { when(mNotificationEntryManager.getPendingNotificationsIterator()) .thenReturn(mPendingEntries.values()); - mGroupManager = new NotificationGroupManager( + mGroupManager = new NotificationGroupManagerLegacy( mock(StatusBarStateController.class), () -> mock(PeopleNotificationIdentifier.class)); - mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager); + mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, mGroupManager); mGroupManager.setHeadsUpManager(mHeadsUpManager); when(mBindStage.getStageParams(any())).thenReturn(new RowContentBindParams()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java index 5a6f74a4c6aa..0aa009134440 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java @@ -33,6 +33,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -47,11 +48,11 @@ import org.mockito.junit.MockitoRule; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper -public class NotificationGroupManagerTest extends SysuiTestCase { +public class NotificationGroupManagerLegacyTest extends SysuiTestCase { @Rule public MockitoRule rule = MockitoJUnit.rule(); - private NotificationGroupManager mGroupManager; + private NotificationGroupManagerLegacy mGroupManager; private final NotificationGroupTestHelper mGroupTestHelper = new NotificationGroupTestHelper(mContext); @@ -64,7 +65,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase { } private void initializeGroupManager() { - mGroupManager = new NotificationGroupManager( + mGroupManager = new NotificationGroupManagerLegacy( mock(StatusBarStateController.class), () -> mock(PeopleNotificationIdentifier.class)); mGroupManager.setHeadsUpManager(mHeadsUpManager); @@ -78,7 +79,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase { mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); - assertTrue(mGroupManager.isOnlyChildInGroup(childEntry.getSbn())); + assertTrue(mGroupManager.isOnlyChildInGroup(childEntry)); } @Test @@ -90,7 +91,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase { mGroupManager.onEntryAdded(childEntry); mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); - assertTrue(mGroupManager.isChildInGroupWithSummary(childEntry.getSbn())); + assertTrue(mGroupManager.isChildInGroup(childEntry)); } @Test @@ -102,8 +103,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase { mGroupManager.onEntryAdded(childEntry); mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); - assertTrue(mGroupManager.isSummaryOfGroup(summaryEntry.getSbn())); - assertEquals(summaryEntry, mGroupManager.getGroupSummary(childEntry.getSbn())); + assertTrue(mGroupManager.isGroupSummary(summaryEntry)); + assertEquals(summaryEntry, mGroupManager.getGroupSummary(childEntry)); } @Test @@ -116,7 +117,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase { mGroupManager.onEntryRemoved(childEntry); - assertFalse(mGroupManager.isChildInGroupWithSummary(childEntry.getSbn())); + assertFalse(mGroupManager.isChildInGroup(childEntry)); } @Test @@ -129,8 +130,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase { mGroupManager.onEntryRemoved(summaryEntry); - assertNull(mGroupManager.getGroupSummary(childEntry.getSbn())); - assertFalse(mGroupManager.isSummaryOfGroup(summaryEntry.getSbn())); + assertNull(mGroupManager.getGroupSummary(childEntry)); + assertFalse(mGroupManager.isGroupSummary(summaryEntry)); } @Test @@ -146,7 +147,7 @@ public class NotificationGroupManagerTest extends SysuiTestCase { // Child entries that are heads upped should be considered separate groups visually even if // they are the same group logically - assertEquals(childEntry, mGroupManager.getGroupSummary(childEntry.getSbn())); - assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(childEntry.getSbn())); + assertEquals(childEntry, mGroupManager.getGroupSummary(childEntry)); + assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(childEntry)); } } 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 453baa5e16fd..cf64ff2f8cd6 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 @@ -74,12 +74,12 @@ import com.android.systemui.statusbar.notification.ConversationNotificationManag import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.InjectionInflationController; import org.junit.Before; @@ -118,7 +118,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private NotificationShelfController mNotificationShelfController; @Mock - private NotificationGroupManager mGroupManager; + private NotificationGroupManagerLegacy mGroupManager; @Mock private KeyguardStatusBarView mKeyguardStatusBar; @Mock @@ -174,8 +174,6 @@ public class NotificationPanelViewTest extends SysuiTestCase { private KeyguardClockSwitch mKeyguardClockSwitch; private PanelViewController.TouchHandler mTouchHandler; @Mock - private ZenModeController mZenModeController; - @Mock private ConfigurationController mConfigurationController; @Mock private MediaHierarchyManager mMediaHiearchyManager; @@ -259,16 +257,16 @@ public class NotificationPanelViewTest extends SysuiTestCase { mKeyguardStateController, mStatusBarStateController, mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper, mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor, - mMetricsLogger, mActivityManager, mZenModeController, mConfigurationController, + mMetricsLogger, mActivityManager, mConfigurationController, flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager, mConversationNotificationManager, mMediaHiearchyManager, mBiometricUnlockController, mStatusBarKeyguardViewManager, mNotificationStackScrollLayoutController, - mNotificationAreaController, - mKeyguardStatusViewComponentFactory); + mKeyguardStatusViewComponentFactory, + mGroupManager, + mNotificationAreaController); mNotificationPanelViewController.initDependencies( mStatusBar, - mGroupManager, mNotificationShelfController); mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); mNotificationPanelViewController.setBar(mPanelBar); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 2f4511329041..108327341f94 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.eq; @@ -27,7 +28,6 @@ import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.Context; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.View; @@ -39,14 +39,13 @@ import androidx.test.filters.SmallTest; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; +import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.SysuiTestCase; -import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.FaceAuthScreenBrightnessController; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -71,8 +70,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Mock private LockPatternUtils mLockPatternUtils; @Mock - private KeyguardBouncer mBouncer; - @Mock private KeyguardStateController mKeyguardStateController; @Mock private StatusBar mStatusBar; @@ -94,6 +91,13 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { private KeyguardBypassController mBypassController; @Mock private FaceAuthScreenBrightnessController mFaceAuthScreenBrightnessController; + @Mock + private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; + @Mock + private KeyguardBouncerComponent mKeyguardBouncerComponent; + @Mock + private KeyguardBouncer mBouncer; + private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Before @@ -102,7 +106,14 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { when(mLockIconContainer.getParent()).thenReturn(mock(ViewGroup.class)); when(mLockIconContainer.animate()).thenReturn(mock(ViewPropertyAnimator.class, RETURNS_DEEP_STUBS)); - mStatusBarKeyguardViewManager = new TestableStatusBarKeyguardViewManager( + + when(mKeyguardBouncerComponentFactory.build( + any(ViewGroup.class), + any(KeyguardBouncer.BouncerExpansionCallback.class))) + .thenReturn(mKeyguardBouncerComponent); + when(mKeyguardBouncerComponent.createKeyguardBouncer()).thenReturn(mBouncer); + + mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager( getContext(), mViewMediatorCallback, mLockPatternUtils, @@ -113,12 +124,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mock(DockManager.class), mock(NotificationShadeWindowController.class), mKeyguardStateController, - mFaceAuthScreenBrightnessController, - mock(NotificationMediaManager.class)); + Optional.of(mFaceAuthScreenBrightnessController), + mock(NotificationMediaManager.class), + mKeyguardBouncerComponentFactory); mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer, - mNotificationPanelView, mBiometrucUnlockController, mDismissCallbackRegistry, - mLockIconContainer, mNotificationContainer, mBypassController, - new FalsingManagerFake()); + mNotificationPanelView, mBiometrucUnlockController, + mLockIconContainer, mNotificationContainer, mBypassController); mStatusBarKeyguardViewManager.show(null); } @@ -267,38 +278,4 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { verify(action).onDismiss(); verify(cancelAction, never()).run(); } - - private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager { - - public TestableStatusBarKeyguardViewManager(Context context, - ViewMediatorCallback callback, - LockPatternUtils lockPatternUtils, - SysuiStatusBarStateController sysuiStatusBarStateController, - ConfigurationController configurationController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - NavigationModeController navigationModeController, - DockManager dockManager, - NotificationShadeWindowController notificationShadeWindowController, - KeyguardStateController keyguardStateController, - FaceAuthScreenBrightnessController faceAuthScreenBrightnessController, - NotificationMediaManager notificationMediaManager) { - super(context, callback, lockPatternUtils, sysuiStatusBarStateController, - configurationController, keyguardUpdateMonitor, navigationModeController, - dockManager, notificationShadeWindowController, keyguardStateController, - Optional.of(faceAuthScreenBrightnessController), notificationMediaManager); - } - - @Override - public void registerStatusBar(StatusBar statusBar, ViewGroup container, - NotificationPanelViewController notificationPanelViewController, - BiometricUnlockController fingerprintUnlockController, - DismissCallbackRegistry dismissCallbackRegistry, - ViewGroup lockIconContainer, View notificationContainer, - KeyguardBypassController bypassController, FalsingManager falsingManager) { - super.registerStatusBar(statusBar, container, notificationPanelViewController, - fingerprintUnlockController, dismissCallbackRegistry, lockIconContainer, - notificationContainer, bypassController, falsingManager); - mBouncer = StatusBarKeyguardViewManagerTest.this.mBouncer; - } - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 3f631b1f6282..792637d8479b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -67,9 +67,9 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; @@ -122,8 +122,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { private FeatureFlags mFeatureFlags; @Mock private NotifPipeline mNotifPipeline; - @Mock - private NotifCollection mNotifCollection; @Mock private ActivityIntentHelper mActivityIntentHelper; @@ -187,7 +185,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mUiBgExecutor, mEntryManager, mNotifPipeline, - mNotifCollection, mock(HeadsUpManagerPhone.class), mActivityStarter, mClickNotifier, @@ -198,7 +195,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mBubbleController, () -> mAssistManager, mRemoteInputManager, - mock(NotificationGroupManager.class), + mock(NotificationGroupManagerLegacy.class), mock(NotificationLockscreenUserManager.class), mShadeController, mKeyguardStateController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java index bf2bd38638ff..6fbbee22a73c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java @@ -36,6 +36,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -72,7 +73,7 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { mNotificationLockscreenUserManager); mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext, - mock(NotificationGroupManager.class), mNotificationLockscreenUserManager, + mock(NotificationGroupManagerLegacy.class), mNotificationLockscreenUserManager, mKeyguardStateController, mStatusBarStateController, mStatusBarKeyguardViewManager, mActivityStarter, mShadeController, new CommandQueue(mContext), mock(ActionClickLogger.class))); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 87aee3fd4794..5143596f0214 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -220,7 +220,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private NetworkController mNetworkController; @Mock private VibratorHelper mVibratorHelper; @Mock private BubbleController mBubbleController; - @Mock private NotificationGroupManager mGroupManager; @Mock private NotificationShadeWindowController mNotificationShadeWindowController; @Mock private NotificationIconAreaController mNotificationIconAreaController; @Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController; @@ -376,7 +375,6 @@ public class StatusBarTest extends SysuiTestCase { mStatusBarStateController, mVibratorHelper, mBubbleController, - mGroupManager, mVisualStabilityManager, mDeviceProvisionedController, mNavigationBarController, 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 070626be9f80..c70dfcc93e49 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 @@ class EventDispatcher { 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 @@ class EventDispatcher { } /** + * 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 07e82111d4e5..5b46cb4ab378 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 @@ class MultiFingerSwipe extends GestureMatcher { + 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 adccf6cfc99c..8305be393ab1 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 @@ public class TouchExplorer extends BaseEventStreamTransformation mReceivedPointerTracker.getReceivedPointerDownY(id) - rawEvent.getY(index); final double moveDelta = Math.hypot(deltaX, deltaY); - if (moveDelta < mTouchSlop) { + if (moveDelta < (2 * mTouchSlop)) { return; } } @@ -651,7 +651,13 @@ public class TouchExplorer extends BaseEventStreamTransformation 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); + } } } } 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 3ee5b28ee338..7d6067c8e1da 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 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl Slog.i(LOG_TAG, "onDestroy(); delayed = " + mDetectingState.toString()); } - mWindowMagnificationMgr.disableWindowMagnifier(mDisplayId, true); + mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true); resetToDetectState(); } @@ -211,14 +211,14 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl 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 ed2b26f24478..ecbece6f1f27 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 class WindowMagnificationManager implements public void onReceive(Context context, Intent intent) { final int displayId = context.getDisplayId(); removeMagnificationButton(displayId); - disableWindowMagnification(displayId); + disableWindowMagnification(displayId, false); } }; @@ -136,10 +136,10 @@ public class WindowMagnificationManager implements /** * 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 @@ public class WindowMagnificationManager implements 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 @@ public class WindowMagnificationManager implements @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 @@ public class WindowMagnificationManager implements } /** - * 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 @@ public class WindowMagnificationManager implements * @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 @@ public class WindowMagnificationManager implements } /** - * 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 @@ public class WindowMagnificationManager implements } /** - * 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 @@ public class WindowMagnificationManager implements * @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 @@ public class WindowMagnificationManager implements } /** - * 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 @@ public class WindowMagnificationManager implements 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 @@ public class WindowMagnificationManager implements } @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 @@ public class WindowMagnificationManager implements } @GuardedBy("mLock") - void disable() { - if (mEnabled && mWindowMagnificationManager.disableWindowMagnification(mDisplayId)) { + void disableWindowMagnificationInternal() { + if (mEnabled && mWindowMagnificationManager.disableWindowMagnificationInternal( + mDisplayId)) { mEnabled = false; } } @@ -519,7 +521,7 @@ public class WindowMagnificationManager implements } } - 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 @@ public class WindowMagnificationManager implements 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/companion/TEST_MAPPING b/services/companion/TEST_MAPPING new file mode 100644 index 000000000000..63f54fa35158 --- /dev/null +++ b/services/companion/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "CtsOsTestCases", + "options": [ + { + "include-filter": "android.os.cts.CompanionDeviceManagerTest" + } + ] + } + ] +} diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 35e88eb804cb..7d81d412e369 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -2114,7 +2114,7 @@ public class AccountManagerService * Owner or system user account was renamed, rename the account for * those users with which the account was shared. */ - List<UserInfo> users = getUserManager().getUsers(true); + List<UserInfo> users = getUserManager().getAliveUsers(); for (UserInfo user : users) { if (user.isRestricted() && (user.restrictedProfileParentId == parentUserId)) { @@ -2373,7 +2373,7 @@ public class AccountManagerService int parentUserId = accounts.userId; if (canHaveProfile(parentUserId)) { // Remove from any restricted profiles that are sharing this account. - List<UserInfo> users = getUserManager().getUsers(true); + List<UserInfo> users = getUserManager().getAliveUsers(); for (UserInfo user : users) { if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) { removeSharedAccountAsUser(account, user.id, callingUid); @@ -4267,7 +4267,7 @@ public class AccountManagerService */ @NonNull public AccountAndUser[] getAllAccounts() { - final List<UserInfo> users = getUserManager().getUsers(true); + final List<UserInfo> users = getUserManager().getAliveUsers(); final int[] userIds = new int[users.size()]; for (int i = 0; i < userIds.length; i++) { userIds[i] = users.get(i).id; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2d803437beb9..1502b7e0355c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -17144,8 +17144,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public int checkContentProviderUriPermission(Uri uri, int userId, int callingUid, int modeFlags) { - return mCpHelper.checkContentProviderUriPermission(uri, - userId, callingUid, modeFlags); + return mCpHelper.checkContentProviderUriPermission(uri, userId, callingUid, modeFlags); } @Override diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java index bfba4afcd4e4..05a731d2b50b 100644 --- a/services/core/java/com/android/server/am/ContentProviderHelper.java +++ b/services/core/java/com/android/server/am/ContentProviderHelper.java @@ -198,22 +198,10 @@ public class ContentProviderHelper { if (providerRunning) { cpi = cpr.info; - String msg; if (r != null && cpr.canRunHere(r)) { - if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) { - throw new SecurityException("Content provider lookup " - + cpr.name.flattenToShortString() - + " failed: association not allowed with package " + msg); - } - checkTime(startTime, - "getContentProviderImpl: before checkContentProviderPermission"); - if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser)) - != null) { - throw new SecurityException(msg); - } - checkTime(startTime, - "getContentProviderImpl: after checkContentProviderPermission"); + checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser, + cpr.name.flattenToShortString(), startTime); // This provider has been published or is in the process // of being published... but it is also allowed to run @@ -234,26 +222,14 @@ public class ContentProviderHelper { } catch (RemoteException e) { } - if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) { - throw new SecurityException( - "Content provider lookup " + cpr.name.flattenToShortString() - + " failed: association not allowed with package " + msg); - } - checkTime(startTime, - "getContentProviderImpl: before checkContentProviderPermission"); - if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser)) - != null) { - throw new SecurityException(msg); - } - checkTime(startTime, - "getContentProviderImpl: after checkContentProviderPermission"); + checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser, + cpr.name.flattenToShortString(), startTime); final long origId = Binder.clearCallingIdentity(); checkTime(startTime, "getContentProviderImpl: incProviderCountLocked"); - // In this case the provider instance already exists, so we can - // return it right away. + // In this case the provider instance already exists so we can return it right away. conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag, stable, true, startTime, mService.mProcessList); @@ -328,19 +304,8 @@ public class ContentProviderHelper { cpi.applicationInfo = mService.getAppInfoForUser(cpi.applicationInfo, userId); checkTime(startTime, "getContentProviderImpl: got app info for user"); - String msg; - if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) { - throw new SecurityException("Content provider lookup " + name - + " failed: association not allowed with package " + msg); - } - checkTime(startTime, - "getContentProviderImpl: before checkContentProviderPermission"); - if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton)) - != null) { - throw new SecurityException(msg); - } - checkTime(startTime, - "getContentProviderImpl: after checkContentProviderPermission"); + checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, !singleton, + name, startTime); if (!mService.mProcessesReady && !cpi.processName.equals("system")) { // If this content provider does not run in the system @@ -352,10 +317,12 @@ public class ContentProviderHelper { // If system providers are not installed yet we aggressively crash to avoid // creating multiple instance of these providers and then bad things happen! - if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp() - && "system".equals(cpi.processName)) { - throw new IllegalStateException("Cannot access system provider: '" - + cpi.authority + "' before system providers are installed!"); + synchronized (this) { + if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp() + && "system".equals(cpi.processName)) { + throw new IllegalStateException("Cannot access system provider: '" + + cpi.authority + "' before system providers are installed!"); + } } // Make sure that the user who owns this provider is running. If not, @@ -605,6 +572,23 @@ public class ContentProviderHelper { return cpr.newHolder(conn, false); } + private void checkAssociationAndPermissionLocked(ProcessRecord callingApp, ProviderInfo cpi, + int callingUid, int userId, boolean checkUser, String cprName, long startTime) { + String msg; + if ((msg = checkContentProviderAssociation(callingApp, callingUid, cpi)) != null) { + throw new SecurityException("Content provider lookup " + cprName + + " failed: association not allowed with package " + msg); + } + checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission"); + if ((msg = checkContentProviderPermission( + cpi, Binder.getCallingPid(), Binder.getCallingUid(), userId, checkUser, + callingApp != null ? callingApp.toString() : null)) + != null) { + throw new SecurityException(msg); + } + checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission"); + } + void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) { if (providers == null) { return; @@ -623,7 +607,7 @@ public class ContentProviderHelper { } final long origId = Binder.clearCallingIdentity(); - + boolean providersPublished = false; for (int i = 0, size = providers.size(); i < size; i++) { ContentProviderHolder src = providers.get(i); if (src == null || src.info == null || src.provider == null) { @@ -636,6 +620,7 @@ public class ContentProviderHelper { if (DEBUG_MU) { Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid); } + providersPublished = true; ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name); mProviderMap.putProviderByClass(comp, dst); @@ -673,8 +658,19 @@ public class ContentProviderHelper { dst.onProviderPublishStatusLocked(true); } dst.mRestartCount = 0; + } + + // update the app's oom adj value and each provider's usage stats + if (providersPublished) { mService.updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER); - maybeUpdateProviderUsageStatsLocked(r, src.info.packageName, src.info.authority); + for (int i = 0, size = providers.size(); i < size; i++) { + ContentProviderHolder src = providers.get(i); + if (src == null || src.info == null || src.provider == null) { + continue; + } + maybeUpdateProviderUsageStatsLocked(r, + src.info.packageName, src.info.authority); + } } Binder.restoreCallingIdentity(origId); @@ -997,17 +993,19 @@ public class ContentProviderHelper { + "; expected to find a valid ContentProvider for this authority"; } + final int callingPid = Binder.getCallingPid(); ProcessRecord r; + final String appName; synchronized (mService.mPidsSelfLocked) { - r = mService.mPidsSelfLocked.get(Binder.getCallingPid()); - } - if (r == null) { - return "Failed to find PID " + Binder.getCallingPid(); + r = mService.mPidsSelfLocked.get(callingPid); + if (r == null) { + return "Failed to find PID " + callingPid; + } + appName = r.toString(); } - synchronized (mService) { - return checkContentProviderPermissionLocked(cpi, r, userId, true); - } + return checkContentProviderPermission(cpi, callingPid, Binder.getCallingUid(), + userId, true, appName); } int checkContentProviderUriPermission(Uri uri, int userId, int callingUid, int modeFlags) { @@ -1163,13 +1161,14 @@ public class ContentProviderHelper { } } } - if (providers != null) { - mService.mSystemThread.installSystemProviders(providers); - } - synchronized (mService) { + synchronized (this) { + if (providers != null) { + mService.mSystemThread.installSystemProviders(providers); + } mSystemProvidersInstalled = true; } + mService.mConstants.start(mService.mContext.getContentResolver()); mService.mCoreSettingsObserver = new CoreSettingsObserver(mService); mService.mActivityTaskManager.installSystemProviders(); @@ -1305,10 +1304,8 @@ public class ContentProviderHelper { * given {@link ProviderInfo}. Final permission checking is always done * in {@link ContentProvider}. */ - private String checkContentProviderPermissionLocked(ProviderInfo cpi, ProcessRecord r, - int userId, boolean checkUser) { - final int callingPid = (r != null) ? r.pid : Binder.getCallingPid(); - final int callingUid = (r != null) ? r.uid : Binder.getCallingUid(); + private String checkContentProviderPermission(ProviderInfo cpi, int callingPid, int callingUid, + int userId, boolean checkUser, String appName) { boolean checkedGrants = false; if (checkUser) { // Looking for cross-user grants before enforcing the typical cross-users permissions @@ -1376,8 +1373,8 @@ public class ContentProviderHelper { suffix = " requires " + cpi.readPermission + " or " + cpi.writePermission; } final String msg = "Permission Denial: opening provider " + cpi.name - + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid - + ", uid=" + callingUid + ")" + suffix; + + " from " + (appName != null ? appName : "(null)") + + " (pid=" + callingPid + ", uid=" + callingUid + ")" + suffix; Slog.w(TAG, msg); return msg; } @@ -1398,18 +1395,17 @@ public class ContentProviderHelper { } ProviderInfo getProviderInfoLocked(String authority, @UserIdInt int userId, int pmFlags) { - ProviderInfo pi = null; ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId); if (cpr != null) { - pi = cpr.info; + return cpr.info; } else { try { - pi = AppGlobals.getPackageManager().resolveContentProvider( + return AppGlobals.getPackageManager().resolveContentProvider( authority, PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags, userId); } catch (RemoteException ex) { + return null; } } - return pi; } private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName, @@ -1419,7 +1415,6 @@ public class ContentProviderHelper { return; } - UserState userState = mService.mUserController.getStartedUserState(app.userId); if (userState == null) return; final long now = SystemClock.elapsedRealtime(); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index d59780d7f609..3f29eb5636ea 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -6528,8 +6528,8 @@ public class AudioService extends IAudioService.Stub 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/biometrics/sensors/face/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java index 32bb2db77ddc..d9c62df3f3ea 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java @@ -29,7 +29,6 @@ import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback; import android.hardware.face.Face; -import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorProperties; import android.hardware.face.IFaceServiceReceiver; import android.os.Build; @@ -383,7 +382,7 @@ class Face10 implements IHwBinder.DeathRecipient { // is safe because authenticatorIds only change when A) new template has been enrolled, // or B) all templates are removed. mHandler.post(() -> { - for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) { + for (UserInfo user : UserManager.get(mContext).getAliveUsers()) { final int targetUserId = user.id; if (!mAuthenticatorIds.containsKey(targetUserId)) { scheduleUpdateActiveUserWithoutHandler(targetUserId); @@ -480,7 +479,8 @@ class Face10 implements IHwBinder.DeathRecipient { * notifying the previous caller that the interrupting operation is complete (e.g. the * interrupting client's challenge has been revoked, so that the interrupted client can * start retry logic if necessary). See - * {@link FaceManager.GenerateChallengeCallback#onChallengeInterruptFinished(int)} + * {@link + *android.hardware.face.FaceManager.GenerateChallengeCallback#onChallengeInterruptFinished(int)} * The only case of conflicting challenges is currently resetLockout --> enroll. So, the second * option seems better as it prioritizes the new operation, which is user-facing. */ diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java index c5c28227fd24..3754bd748781 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java @@ -440,7 +440,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { // is safe because authenticatorIds only change when A) new template has been enrolled, // or B) all templates are removed. mHandler.post(() -> { - for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) { + for (UserInfo user : UserManager.get(mContext).getAliveUsers()) { final int targetUserId = user.id; if (!mAuthenticatorIds.containsKey(targetUserId)) { scheduleUpdateActiveUserWithoutHandler(targetUserId); diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index a75a80a606eb..4c63eb488118 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 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse 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 5484bfca5851..7175489614ea 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 @@ public class Vpn { 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/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index ec12a971e445..b33aa0a6fad3 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -367,7 +367,7 @@ public class SyncManager { } private void removeStaleAccounts() { - for (UserInfo user : mUserManager.getUsers(true)) { + for (UserInfo user : mUserManager.getAliveUsers()) { // Skip any partially created/removed users if (user.partial) continue; Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts( @@ -777,7 +777,7 @@ public class SyncManager { if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) { return; } - List<UserInfo> users = mUserManager.getUsers(true); + List<UserInfo> users = mUserManager.getAliveUsers(); final int userCount = users.size(); for (int i = 0; i < userCount; i++) { UserHandle userHandle = users.get(i).getUserHandle(); 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 000000000000..0ccd75dcbdce --- /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/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java index e9a05a8aa16c..715e41c62a05 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java @@ -746,7 +746,7 @@ class LockSettingsStorage { public void dump(IndentingPrintWriter pw) { final UserManager um = UserManager.get(mContext); - for (UserInfo user : um.getUsers(false)) { + for (UserInfo user : um.getUsers()) { File userPath = getSyntheticPasswordDirectoryForUser(user.id); pw.println(String.format("User %d [%s]:", user.id, userPath.getAbsolutePath())); pw.increaseIndent(); diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index a604625460a7..74b7bd76b047 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -1554,7 +1554,7 @@ abstract public class ManagedServices { if (!isEnabledForCurrentProfiles()) { return false; } - return this.userid == userId; + return userId == USER_ALL || userId == this.userid; } public boolean enabledAndUserMatches(int nid) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 04658555f22b..12419a9fcafa 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -262,7 +262,6 @@ import com.android.server.EventLogTags; import com.android.server.IoThread; import com.android.server.LocalServices; import com.android.server.SystemService; -import com.android.server.SystemService.TargetUser; import com.android.server.UiThread; import com.android.server.lights.LightsManager; import com.android.server.lights.LogicalLight; @@ -966,8 +965,7 @@ public class NotificationManagerService extends SystemService { nv.recycle(); } reportUserInteraction(r); - mAssistants.notifyAssistantActionClicked( - r.getSbn(), actionIndex, action, generatedByAssistant); + mAssistants.notifyAssistantActionClicked(r.getSbn(), action, generatedByAssistant); } } @@ -8629,12 +8627,25 @@ public class NotificationManagerService extends SystemService { ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE)); } - private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { + @VisibleForTesting + boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { if (!listener.enabledAndUserMatches(sbn.getUserId())) { return false; } - // TODO: remove this for older listeners. - return true; + return isInteractionVisibleToListener(listener, sbn.getUserId()); + } + + /** + * Returns whether the given assistant should be informed about interactions on the given user. + * + * Normally an assistant would be able to see all interactions on the current user and any + * associated profiles because they are notification listeners, but since NASes have one + * instance per user, we want to filter out interactions that are not for the user that the + * given NAS is bound in. + */ + private boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) { + boolean isAssistantService = mAssistants.isServiceTokenValidLocked(info.service); + return !isAssistantService || info.isSameUser(userId); } private boolean isPackageSuspendedForUser(String pkg, int uid) { @@ -8856,8 +8867,6 @@ public class NotificationManagerService extends SystemService { } protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) { - // There should be only one, but it's a list, so while we enforce - // singularity elsewhere, we keep it general here, to avoid surprises. for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { ArrayList<String> keys = new ArrayList<>(records.size()); for (NotificationRecord r : records) { @@ -8875,6 +8884,8 @@ public class NotificationManagerService extends SystemService { } protected void onPanelRevealed(int items) { + // send to all currently bounds NASes since notifications from both users will appear in + // the panel for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { mHandler.post(() -> { final INotificationListener assistant = (INotificationListener) info.service; @@ -8888,6 +8899,8 @@ public class NotificationManagerService extends SystemService { } protected void onPanelHidden() { + // send to all currently bounds NASes since notifications from both users will appear in + // the panel for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) { mHandler.post(() -> { final INotificationListener assistant = (INotificationListener) info.service; @@ -8976,7 +8989,7 @@ public class NotificationManagerService extends SystemService { } notifyAssistantLocked( sbn, - false /* sameUserOnly */, + true /* sameUserOnly */, (assistant, sbnHolder) -> { try { assistant.onNotificationVisibilityChanged(key, isVisible); @@ -8994,7 +9007,7 @@ public class NotificationManagerService extends SystemService { final String key = sbn.getKey(); notifyAssistantLocked( sbn, - false /* sameUserOnly */, + true /* sameUserOnly */, (assistant, sbnHolder) -> { try { assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded); @@ -9010,7 +9023,7 @@ public class NotificationManagerService extends SystemService { final String key = sbn.getKey(); notifyAssistantLocked( sbn, - false /* sameUserOnly */, + true /* sameUserOnly */, (assistant, sbnHolder) -> { try { assistant.onNotificationDirectReply(key); @@ -9026,7 +9039,7 @@ public class NotificationManagerService extends SystemService { final String key = sbn.getKey(); notifyAssistantLocked( sbn, - false /* sameUserOnly */, + true /* sameUserOnly */, (assistant, sbnHolder) -> { try { assistant.onSuggestedReplySent( @@ -9043,12 +9056,12 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") void notifyAssistantActionClicked( - final StatusBarNotification sbn, int actionIndex, Notification.Action action, + final StatusBarNotification sbn, Notification.Action action, boolean generatedByAssistant) { final String key = sbn.getKey(); notifyAssistantLocked( sbn, - false /* sameUserOnly */, + true /* sameUserOnly */, (assistant, sbnHolder) -> { try { assistant.onActionClicked( @@ -9072,7 +9085,7 @@ public class NotificationManagerService extends SystemService { final StatusBarNotification sbn, final String snoozeCriterionId) { notifyAssistantLocked( sbn, - false /* sameUserOnly */, + true /* sameUserOnly */, (assistant, sbnHolder) -> { try { assistant.onNotificationSnoozedUntilContext( @@ -9129,7 +9142,7 @@ public class NotificationManagerService extends SystemService { } protected void resetDefaultAssistantsIfNecessary() { - final List<UserInfo> activeUsers = mUm.getUsers(true); + final List<UserInfo> activeUsers = mUm.getAliveUsers(); for (UserInfo userInfo : activeUsers) { int userId = userInfo.getUserHandle().getIdentifier(); if (!hasUserSet(userId)) { @@ -9293,10 +9306,12 @@ public class NotificationManagerService extends SystemService { } public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) { + // send to all currently bounds NASes since notifications from both users will appear in + // the status bar for (final ManagedServiceInfo info : getServices()) { mHandler.post(() -> { final INotificationListener listener = (INotificationListener) info.service; - try { + try { listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons); } catch (RemoteException ex) { Slog.e(TAG, "unable to notify listener " @@ -9470,7 +9485,8 @@ public class NotificationManagerService extends SystemService { && changedHiddenNotifications.size() > 0; for (final ManagedServiceInfo serviceInfo : getServices()) { - if (!serviceInfo.isEnabledForCurrentProfiles()) { + if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener( + serviceInfo, ActivityManager.getCurrentUser())) { continue; } @@ -9489,12 +9505,7 @@ public class NotificationManagerService extends SystemService { final NotificationRankingUpdate update = makeRankingUpdateLocked( serviceInfo); - mHandler.post(new Runnable() { - @Override - public void run() { - notifyRankingUpdate(serviceInfo, update); - } - }); + mHandler.post(() -> notifyRankingUpdate(serviceInfo, update)); } } } @@ -9502,15 +9513,11 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") public void notifyListenerHintsChangedLocked(final int hints) { for (final ManagedServiceInfo serviceInfo : getServices()) { - if (!serviceInfo.isEnabledForCurrentProfiles()) { + if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener( + serviceInfo, ActivityManager.getCurrentUser())) { continue; } - mHandler.post(new Runnable() { - @Override - public void run() { - notifyListenerHintsChanged(serviceInfo, hints); - } - }); + mHandler.post(() -> notifyListenerHintsChanged(serviceInfo, hints)); } } @@ -9562,15 +9569,12 @@ public class NotificationManagerService extends SystemService { public void notifyInterruptionFilterChanged(final int interruptionFilter) { for (final ManagedServiceInfo serviceInfo : getServices()) { - if (!serviceInfo.isEnabledForCurrentProfiles()) { + if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener( + serviceInfo, ActivityManager.getCurrentUser())) { continue; } - mHandler.post(new Runnable() { - @Override - public void run() { - notifyInterruptionFilterChanged(serviceInfo, interruptionFilter); - } - }); + mHandler.post( + () -> notifyInterruptionFilterChanged(serviceInfo, interruptionFilter)); } } @@ -9579,15 +9583,16 @@ public class NotificationManagerService extends SystemService { if (channel == null) { return; } - for (final ManagedServiceInfo serviceInfo : getServices()) { - if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) { + for (final ManagedServiceInfo info : getServices()) { + if (!info.enabledAndUserMatches(UserHandle.getCallingUserId()) + || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) { continue; } BackgroundThread.getHandler().post(() -> { - if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) { + if (info.isSystem || hasCompanionDevice(info)) { notifyNotificationChannelChanged( - serviceInfo, pkg, user, channel, modificationType); + info, pkg, user, channel, modificationType); } }); } @@ -9599,15 +9604,16 @@ public class NotificationManagerService extends SystemService { if (group == null) { return; } - for (final ManagedServiceInfo serviceInfo : getServices()) { - if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) { + for (final ManagedServiceInfo info : getServices()) { + if (!info.enabledAndUserMatches(UserHandle.getCallingUserId()) + || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) { continue; } BackgroundThread.getHandler().post(() -> { - if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) { + if (info.isSystem || hasCompanionDevice(info)) { notifyNotificationChannelGroupChanged( - serviceInfo, pkg, user, group, modificationType); + info, pkg, user, group, modificationType); } }); } @@ -9626,9 +9632,6 @@ public class NotificationManagerService extends SystemService { private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) { - if (!info.enabledAndUserMatches(sbn.getUserId())) { - return; - } final INotificationListener listener = (INotificationListener) info.service; StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); try { diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index a4debc16493a..d7a1ba2a93d4 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -288,7 +288,7 @@ public final class OverlayManagerService extends SystemService { private void initIfNeeded() { final UserManager um = getContext().getSystemService(UserManager.class); - final List<UserInfo> users = um.getUsers(true /*excludeDying*/); + final List<UserInfo> users = um.getAliveUsers(); synchronized (mLock) { final int userCount = users.size(); for (int i = 0; i < userCount; i++) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 4b246c3b330c..162bfee8848d 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -743,9 +743,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements mStagingManager.createSession(session); } - if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) { - mCallbacks.notifySessionCreated(session.sessionId, session.userId); - } + mCallbacks.notifySessionCreated(session.sessionId, session.userId); + writeSessionsAsync(); return sessionId; } @@ -1355,25 +1354,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements class InternalCallback { public void onSessionBadgingChanged(PackageInstallerSession session) { - if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) { - mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId); - } - + mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId); writeSessionsAsync(); } public void onSessionActiveChanged(PackageInstallerSession session, boolean active) { - if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) { - mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, - active); - } + mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, + active); } public void onSessionProgressChanged(PackageInstallerSession session, float progress) { - if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) { - mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, - progress); - } + mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, + progress); } public void onStagedSessionChanged(PackageInstallerSession session) { @@ -1389,17 +1381,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } public void onSessionFinished(final PackageInstallerSession session, boolean success) { - if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) { - mCallbacks.notifySessionFinished(session.sessionId, session.userId, success); - } + mCallbacks.notifySessionFinished(session.sessionId, session.userId, success); mInstallHandler.post(new Runnable() { @Override public void run() { - if (session.isStaged()) { - if (!success) { - mStagingManager.abortSession(session); - } + if (session.isStaged() && !success) { + mStagingManager.abortSession(session); } synchronized (mSessions) { if (!session.isStaged() || !success) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ed62362b04fb..4e429cf362b5 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -3306,8 +3306,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Send broadcast to default launcher only if it's a new install // TODO(b/144270665): Secure the usage of this broadcast. final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING); - if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts() - && (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) { + if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()) { mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /*icon*/), userId); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index bf01fd314207..ffd23788223e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -13882,7 +13882,7 @@ public class PackageManagerService extends IPackageManager.Stub 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; @@ -13958,18 +13958,6 @@ public class PackageManagerService extends IPackageManager.Stub 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( @@ -14553,13 +14541,11 @@ public class PackageManagerService extends IPackageManager.Stub Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.pkg); } - // A restore should be performed at this point if (a) the install - // succeeded, (b) the operation is not an update, and (c) the new - // package has not opted out of backup participation. + // A restore should be requested at this point if (a) the install + // succeeded, (b) the operation is not an update. final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null; - boolean allowBackup = res.pkg != null && res.pkg.isAllowBackup(); - boolean doRestore = !update && allowBackup; + boolean doRestore = !update; // Set up the post-install work request bookkeeping. This will be used // and cleaned up by the post-install event handling regardless of whether @@ -19542,6 +19528,9 @@ public class PackageManagerService extends IPackageManager.Stub } 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; @@ -20641,6 +20630,9 @@ public class PackageManagerService extends IPackageManager.Stub 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. @@ -20689,6 +20681,7 @@ public class PackageManagerService extends IPackageManager.Stub if (packageName == null) { return null; } + int resolveInfosSize = resolveInfos.size(); for (int i = 0; i < resolveInfosSize; i++) { ResolveInfo resolveInfo = resolveInfos.get(i); @@ -20748,6 +20741,11 @@ public class PackageManagerService extends IPackageManager.Stub // 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); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index d137fd05f793..e44c8ab3f7f3 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -760,6 +760,8 @@ public class UserManagerService extends IUserManager.Stub { return null; } + // TODO(b/157921703): replace by getAliveUsers() or remove (so callers + // explicitly call the 3-booleans version) public @NonNull List<UserInfo> getUsers(boolean excludeDying) { return getUsers(/*excludePartial= */ true, excludeDying, /* excludePreCreated= */ true); diff --git a/services/core/java/com/android/server/slice/SliceFullAccessList.java b/services/core/java/com/android/server/slice/SliceFullAccessList.java index 6f5afa207d31..d25ddf877951 100644 --- a/services/core/java/com/android/server/slice/SliceFullAccessList.java +++ b/services/core/java/com/android/server/slice/SliceFullAccessList.java @@ -101,7 +101,7 @@ public class SliceFullAccessList { public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException { // upgrade xml int xmlVersion = XmlUtils.readIntAttribute(parser, ATT_VERSION, 0); - final List<UserInfo> activeUsers = UserManager.get(mContext).getUsers(true); + final List<UserInfo> activeUsers = UserManager.get(mContext).getAliveUsers(); for (UserInfo userInfo : activeUsers) { upgradeXml(xmlVersion, userInfo.getUserHandle().getIdentifier()); } diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 0c85387be695..386f390c6cb9 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -379,7 +379,7 @@ public class TrustManagerService extends SystemService { } private void updateTrustAll() { - List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); + List<UserInfo> userInfos = mUserManager.getAliveUsers(); for (UserInfo userInfo : userInfos) { updateTrust(userInfo.id, 0); } @@ -485,7 +485,7 @@ public class TrustManagerService extends SystemService { List<UserInfo> userInfos; if (userIdOrAll == UserHandle.USER_ALL) { - userInfos = mUserManager.getUsers(true /* excludeDying */); + userInfos = mUserManager.getAliveUsers(); } else { userInfos = new ArrayList<>(); userInfos.add(mUserManager.getUserInfo(userIdOrAll)); @@ -644,7 +644,7 @@ public class TrustManagerService extends SystemService { } List<UserInfo> userInfos; if (userId == UserHandle.USER_ALL) { - userInfos = mUserManager.getUsers(true /* excludeDying */); + userInfos = mUserManager.getAliveUsers(); } else { userInfos = new ArrayList<>(); userInfos.add(mUserManager.getUserInfo(userId)); @@ -1171,7 +1171,7 @@ public class TrustManagerService extends SystemService { fout.println("disabled because the third-party apps can't run yet."); return; } - final List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); + final List<UserInfo> userInfos = mUserManager.getAliveUsers(); mHandler.runWithScissors(new Runnable() { @Override public void run() { diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index be7a6aed7489..f206259b8fe0 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1710,8 +1710,9 @@ class ActivityStarter { mRootWindowContainer.startPowerModeLaunchIfNeeded( false /* forceSend */, mStartActivity); - mTargetStack.startActivityLocked(mStartActivity, topStack.getTopNonFinishingActivity(), - newTask, mKeepCurTransition, mOptions); + mTargetStack.startActivityLocked(mStartActivity, + topStack != null ? topStack.getTopNonFinishingActivity() : null, newTask, + mKeepCurTransition, mOptions); if (mDoResume) { final ActivityRecord topTaskActivity = mStartActivity.getTask().topRunningActivityLocked(); diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index f9e6270aec5d..6182a55b6e52 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2286,10 +2286,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); - if (display.shouldSleep()) { - continue; - } - final boolean curResult = result; boolean resumedOnDisplay = display.reduceOnAllTaskDisplayAreas( (taskDisplayArea, resumed) -> { diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 33935d61ead2..7df2b407557d 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 static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 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 @@ class SurfaceAnimator { 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 @@ class SurfaceAnimator { * 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/Task.java b/services/core/java/com/android/server/wm/Task.java index 19bf451cec05..bfaaf462ed51 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -6348,7 +6348,7 @@ class Task extends WindowContainer<WindowContainer> { return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea()); } - void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity, + void startActivityLocked(ActivityRecord r, @Nullable ActivityRecord focusedTopActivity, boolean newTask, boolean keepCurTransition, ActivityOptions options) { Task rTask = r.getTask(); final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront(); @@ -7585,7 +7585,11 @@ class Task extends WindowContainer<WindowContainer> { // Do not sleep activities in this stack if we're marked as focused and the keyguard // is in the process of going away. if (isFocusedStackOnDisplay() - && mStackSupervisor.getKeyguardController().isKeyguardGoingAway()) { + && mStackSupervisor.getKeyguardController().isKeyguardGoingAway() + // Avoid resuming activities on secondary displays since we don't want bubble + // activities to be resumed while bubble is still collapsed. + // TODO(b/113840485): Having keyguard going away state for secondary displays. + && display.isDefaultDisplay) { return false; } diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 1b779c6a0cc9..63a595e3bc17 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -38,6 +38,7 @@ import android.os.Binder; 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; @@ -50,6 +51,7 @@ import com.android.internal.util.ArrayUtils; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -206,7 +208,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { 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 = @@ -224,10 +225,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { mUid = uid; } - void setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed) { - mInterceptBackPressedOnTaskRoot = interceptBackPressed; - } - void addTask(Task t) { if (t.mTaskAppearedSent) return; @@ -247,6 +244,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { mOrganizer.onTaskVanished(t); } mOrganizedTasks.remove(t); + mInterceptBackPressedOnRootTasks.remove(t.mTaskId); } void dispose() { @@ -278,6 +276,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { 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; @@ -623,7 +623,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } @Override - public void setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer, + public void setInterceptBackPressedOnTaskRoot(WindowContainerToken token, boolean interceptBackPressed) { enforceStackPermission("setInterceptBackPressedOnTaskRoot()"); final long origId = Binder.clearCallingIdentity(); @@ -631,9 +631,15 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { synchronized (mGlobalLock) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set intercept back pressed on root=%b", interceptBackPressed); - final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder()); - if (state != null) { - state.setInterceptBackPressedOnTaskRoot(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 { @@ -642,15 +648,12 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } 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/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 22e309cdc2b4..80455833a3eb 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -5782,9 +5782,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (!mHasFeature) { return; } - final CallerIdentity identity = getCallerIdentity(); - Preconditions.checkCallAuthorization(isSystemUid(identity) || isRootUid(identity) - || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL)); final ActiveAdmin admin; synchronized (getLockObject()) { @@ -9438,8 +9435,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkCallAuthorization(isDeviceOwner(identity)); return mInjector.binderWithCleanCallingIdentity(() -> { - final List<UserInfo> userInfos = mInjector.getUserManager().getUsers(true - /*excludeDying*/); + final List<UserInfo> userInfos = mInjector.getUserManager().getAliveUsers(); final List<UserHandle> userHandles = new ArrayList<>(); for (UserInfo userInfo : userInfos) { UserHandle userHandle = userInfo.getUserHandle(); @@ -10362,7 +10358,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private void maybeClearLockTaskPolicyLocked() { mInjector.binderWithCleanCallingIdentity(() -> { - final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true); + final List<UserInfo> userInfos = mUserManager.getAliveUsers(); for (int i = userInfos.size() - 1; i >= 0; i--) { int userId = userInfos.get(i).id; if (canUserUseLockTaskLocked(userId)) { @@ -10849,7 +10845,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * them. */ void updateUserSetupCompleteAndPaired() { - List<UserInfo> users = mUserManager.getUsers(true); + List<UserInfo> users = mUserManager.getAliveUsers(); final int N = users.size(); for (int i = 0; i < N; i++) { int userHandle = users.get(i).id; @@ -12052,14 +12048,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @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); @@ -12579,7 +12567,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private boolean areAllUsersAffiliatedWithDeviceLocked() { return mInjector.binderWithCleanCallingIdentity(() -> { - final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true); + final List<UserInfo> userInfos = mUserManager.getAliveUsers(); for (int i = 0; i < userInfos.size(); i++) { int userId = userInfos.get(i).id; if (!isUserAffiliatedWithDeviceLocked(userId)) { @@ -13048,7 +13036,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } else { // Caller is the device owner: Look for profile owners that it can bind to. - final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true); + final List<UserInfo> userInfos = mUserManager.getAliveUsers(); for (int i = 0; i < userInfos.size(); i++) { final int userId = userInfos.get(i).id; if (userId != callingUserId && canUserBindToDeviceOwnerLocked(userId)) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java index 3cdd482ffa37..7649af4ee911 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java @@ -169,7 +169,7 @@ class Owners { // First, try to read from the legacy file. final File legacy = getLegacyConfigFile(); - final List<UserInfo> users = mUserManager.getUsers(true); + final List<UserInfo> users = mUserManager.getAliveUsers(); if (readLegacyOwnerFileLocked(legacy)) { if (DEBUG) { 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 bec9f26672f4..a10e0ba5020c 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 @@ public class WindowMagnificationGestureHandlerTest { @After public void tearDown() { - mWindowMagnificationManager.disableWindowMagnifier(DISPLAY_0, true); + mWindowMagnificationManager.disableWindowMagnification(DISPLAY_0, true); } @Test @@ -225,7 +225,7 @@ public class WindowMagnificationGestureHandlerTest { } 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 70e6a340816a..e067b7eca755 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 @@ public class WindowMagnificationManagerTest { 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 @@ public class WindowMagnificationManagerTest { 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 class WindowMagnificationManagerTest { 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 @@ public class WindowMagnificationManagerTest { @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 @@ public class WindowMagnificationManagerTest { 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 @@ public class WindowMagnificationManagerTest { @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 @@ public class WindowMagnificationManagerTest { @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 @@ public class WindowMagnificationManagerTest { @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 @@ public class WindowMagnificationManagerTest { @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 @@ public class WindowMagnificationManagerTest { @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 @@ public class WindowMagnificationManagerTest { @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 @@ public class WindowMagnificationManagerTest { 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 @@ public class WindowMagnificationManagerTest { @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/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index b306ff091267..431cc27a6635 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -16,7 +16,6 @@ package com.android.server.devicepolicy; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; @@ -236,7 +235,7 @@ public class MockSystemServices { } mUserInfos.add(uh); when(userManager.getUsers()).thenReturn(mUserInfos); - when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos); + when(userManager.getAliveUsers()).thenReturn(mUserInfos); when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true); when(userManager.getProfileParent(anyInt())).thenAnswer( invocation -> { 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 ef2365e6da3e..3f324a279270 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 @@ public class HdmiCecLocalDevicePlaybackTest { } @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/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java index 99433a6603c9..d7e431f3bb51 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java @@ -978,6 +978,7 @@ public class ManagedServicesTest extends UiServiceTestCase { assertFalse(services.isSameUser(service, 0)); assertTrue(services.isSameUser(service, 10)); + assertTrue(services.isSameUser(service, UserHandle.USER_ALL)); } @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java index ab4dc476ff20..5796e848ff6e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java @@ -103,7 +103,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { when(mUm.getUserInfo(eq(user.id))).thenReturn(user); } when(mUm.getUsers()).thenReturn(users); - when(mUm.getUsers(anyBoolean())).thenReturn(users); + when(mUm.getAliveUsers()).thenReturn(users); IntArray profileIds = new IntArray(); profileIds.add(0); profileIds.add(11); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 9319bea497fb..86447192a441 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -5058,7 +5058,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 10, 10, r.getKey(), actionIndex, action, notificationVisibility, generatedByAssistant); verify(mAssistants).notifyAssistantActionClicked( - eq(r.getSbn()), eq(actionIndex), eq(action), eq(generatedByAssistant)); + eq(r.getSbn()), eq(action), eq(generatedByAssistant)); assertEquals(1, mNotificationRecordLogger.numCalls()); assertEquals( @@ -5082,7 +5082,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 10, 10, r.getKey(), actionIndex, action, notificationVisibility, generatedByAssistant); verify(mAssistants).notifyAssistantActionClicked( - eq(r.getSbn()), eq(actionIndex), eq(action), eq(generatedByAssistant)); + eq(r.getSbn()), eq(action), eq(generatedByAssistant)); assertEquals(1, mNotificationRecordLogger.numCalls()); assertEquals( @@ -6948,4 +6948,63 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, mService.getNotificationRecordCount()); } + + @Test + public void testIsVisibleToListener_notEnabled() { + StatusBarNotification sbn = mock(StatusBarNotification.class); + when(sbn.getUserId()).thenReturn(10); + ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); + ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); + info.userid = 10; + when(info.isSameUser(anyInt())).thenReturn(true); + when(assistant.isSameUser(anyInt())).thenReturn(true); + when(info.enabledAndUserMatches(info.userid)).thenReturn(false); + when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); + + assertFalse(mService.isVisibleToListener(sbn, info)); + } + + @Test + public void testIsVisibleToListener_noAssistant() { + StatusBarNotification sbn = mock(StatusBarNotification.class); + when(sbn.getUserId()).thenReturn(10); + ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); + info.userid = 10; + when(info.isSameUser(anyInt())).thenReturn(true); + when(info.enabledAndUserMatches(info.userid)).thenReturn(true); + when(mAssistants.checkServiceTokenLocked(any())).thenReturn(null); + + assertTrue(mService.isVisibleToListener(sbn, info)); + } + + @Test + public void testIsVisibleToListener_assistant_differentUser() { + StatusBarNotification sbn = mock(StatusBarNotification.class); + when(sbn.getUserId()).thenReturn(10); + ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); + ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); + info.userid = 0; + when(info.isSameUser(anyInt())).thenReturn(true); + when(assistant.isSameUser(anyInt())).thenReturn(true); + when(info.enabledAndUserMatches(info.userid)).thenReturn(true); + when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); + + assertFalse(mService.isVisibleToListener(sbn, info)); + } + + @Test + public void testIsVisibleToListener_assistant_sameUser() { + StatusBarNotification sbn = mock(StatusBarNotification.class); + when(sbn.getUserId()).thenReturn(10); + ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); + ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); + info.userid = 10; + when(info.isSameUser(anyInt())).thenReturn(true); + when(assistant.isSameUser(anyInt())).thenReturn(true); + when(info.enabledAndUserMatches(info.userid)).thenReturn(true); + when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); + + assertTrue(mService.isVisibleToListener(sbn, info)); + } + } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index e2948a724acd..4cad39762a7b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -1202,19 +1202,22 @@ public class ActivityStackTests extends WindowTestsBase { @Test public void testShouldSleepActivities() { // When focused activity and keyguard is going away, we should not sleep regardless - // of the display state + // of the display state, but keyguard-going-away should only take effects on default + // display since there is no keyguard on secondary displays (yet). verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/, - true /* displaySleeping */, false /* expected*/); + true /* displaySleeping */, true /* isDefaultDisplay */, false /* expected */); + verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/, + true /* displaySleeping */, false /* isDefaultDisplay */, true /* expected */); // When not the focused stack, defer to display sleeping state. verifyShouldSleepActivities(false /* focusedStack */, true /*keyguardGoingAway*/, - true /* displaySleeping */, true /* expected*/); + true /* displaySleeping */, true /* isDefaultDisplay */, true /* expected */); // If keyguard is going away, defer to the display sleeping state. verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/, - true /* displaySleeping */, true /* expected*/); + true /* displaySleeping */, true /* isDefaultDisplay */, true /* expected */); verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/, - false /* displaySleeping */, false /* expected*/); + false /* displaySleeping */, true /* isDefaultDisplay */, false /* expected */); } @Test @@ -1423,9 +1426,11 @@ public class ActivityStackTests extends WindowTestsBase { } private void verifyShouldSleepActivities(boolean focusedStack, - boolean keyguardGoingAway, boolean displaySleeping, boolean expected) { + boolean keyguardGoingAway, boolean displaySleeping, boolean isDefaultDisplay, + boolean expected) { final DisplayContent display = mock(DisplayContent.class); final KeyguardController keyguardController = mSupervisor.getKeyguardController(); + display.isDefaultDisplay = isDefaultDisplay; doReturn(display).when(mStack).getDisplay(); doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index b89d16807a6e..26b0bfb1dd7c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -915,24 +915,6 @@ public class RootActivityContainerTests extends WindowTestsBase { assertEquals(taskDisplayArea.getTopStack(), taskDisplayArea.getRootHomeTask()); } - @Test - public void testResumeFocusedStackOnSleepingDisplay() { - // Create an activity on secondary display. - final TestDisplayContent secondDisplay = addNewDisplayContentAt( - DisplayContent.POSITION_TOP); - final Task stack = secondDisplay.getDefaultTaskDisplayArea() - .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityRecord activity = new ActivityBuilder(mAtm).setStack(stack).build(); - spyOn(activity); - spyOn(stack); - - // Cannot resumed activities on secondary display if the display should sleep. - doReturn(true).when(secondDisplay).shouldSleep(); - mRootWindowContainer.resumeFocusedStacksTopActivities(); - verify(stack, never()).resumeTopActivityUncheckedLocked(any(), any()); - verify(activity, never()).makeActiveIfNeeded(any()); - } - /** * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity * info for test cases. 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 289d54e967f5..46a6a82faba5 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 @@ public class WindowOrganizerTests extends WindowTestsBase { 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 81aad972898e..f151d9ca2420 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 @@ public class UsageStatsService extends SystemService implements 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 @@ public class UsageStatsService extends SystemService implements 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 @@ public class UsageStatsService extends SystemService implements .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 @@ public class UsageStatsService extends SystemService implements } 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 @@ public class UsageStatsService extends SystemService implements 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/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp index 4f5a30502c91..7dd003eb9755 100644 --- a/tests/RollbackTest/Android.bp +++ b/tests/RollbackTest/Android.bp @@ -15,6 +15,7 @@ android_test { name: "RollbackTest", manifest: "RollbackTest/AndroidManifest.xml", + platform_apis: true, srcs: ["RollbackTest/src/**/*.java"], static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"], test_suites: ["general-tests"], diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java index de51c5ca19ed..0db2b2af7260 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java @@ -175,7 +175,7 @@ public class RollbackTest { assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); UserManager um = (UserManager) context.getSystemService(context.USER_SERVICE); - List<Integer> userIds = um.getUsers(true) + List<Integer> userIds = um.getAliveUsers() .stream().map(user -> user.id).collect(Collectors.toList()); assertThat(InstallUtils.isOnlyInstalledForUser(TestApp.A, context.getUserId(), userIds)).isTrue(); 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 f50d2e134730..702f8719ff24 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 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { 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 a3673df1c713..bcb5c992f162 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -1199,7 +1199,7 @@ public class ConnectivityServiceTest { 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 5a29c2c96ba7..de35f910d53a 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 @@ public class PermissionMonitorTest { 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 e8c4ee9c628d..c76b4cd501e7 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 @@ public class VpnTest { * @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]; diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index aa3a13925894..9302f78b7fca 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -81,6 +81,12 @@ public final class ScanResult implements Parcelable { public String capabilities; /** + * The interface name on which the scan result was received. + * @hide + */ + public String ifaceName; + + /** * @hide * No security protocol. */ @@ -939,6 +945,7 @@ public final class ScanResult implements Parcelable { flags = source.flags; radioChainInfos = source.radioChainInfos; this.mWifiStandard = source.mWifiStandard; + this.ifaceName = source.ifaceName; } } @@ -977,6 +984,7 @@ public final class ScanResult implements Parcelable { sb.append(", 80211mcResponder: "); sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported"); sb.append(", Radio Chain Infos: ").append(Arrays.toString(radioChainInfos)); + sb.append(", interface name: ").append(ifaceName); return sb.toString(); } @@ -1056,6 +1064,7 @@ public final class ScanResult implements Parcelable { } else { dest.writeInt(0); } + dest.writeString((ifaceName != null) ? ifaceName.toString() : ""); } /** Implement the Parcelable interface */ @@ -1134,6 +1143,7 @@ public final class ScanResult implements Parcelable { sr.radioChainInfos[i].level = in.readInt(); } } + sr.ifaceName = in.readString(); return sr; } diff --git a/wifi/tests/src/android/net/wifi/ScanResultTest.java b/wifi/tests/src/android/net/wifi/ScanResultTest.java index 5516f433070f..4a3586826de9 100644 --- a/wifi/tests/src/android/net/wifi/ScanResultTest.java +++ b/wifi/tests/src/android/net/wifi/ScanResultTest.java @@ -44,6 +44,7 @@ public class ScanResultTest { public static final long TEST_TSF = 04660l; public static final @WifiAnnotations.WifiStandard int TEST_WIFI_STANDARD = ScanResult.WIFI_STANDARD_11AC; + public static final String TEST_IFACE_NAME = "test_ifname"; /** * Frequency to channel map. This include some frequencies used outside the US. @@ -219,7 +220,7 @@ public class ScanResultTest { + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, " + "standard: 11ac, " + "80211mcResponder: is not supported, " - + "Radio Chain Infos: null", scanResult.toString()); + + "Radio Chain Infos: null, interface name: test_ifname", scanResult.toString()); } /** @@ -242,7 +243,8 @@ public class ScanResultTest { + "standard: 11ac, " + "80211mcResponder: is not supported, " + "Radio Chain Infos: [RadioChainInfo: id=0, level=-45, " - + "RadioChainInfo: id=1, level=-54]", scanResult.toString()); + + "RadioChainInfo: id=1, level=-54], interface name: test_ifname", + scanResult.toString()); } /** @@ -283,6 +285,8 @@ public class ScanResultTest { result.frequency = TEST_FREQUENCY; result.timestamp = TEST_TSF; result.setWifiStandard(TEST_WIFI_STANDARD); + result.ifaceName = TEST_IFACE_NAME; + return result; } |