diff options
98 files changed, 1459 insertions, 886 deletions
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java index 4b7a7f624a3e..32107b4e789e 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java @@ -119,9 +119,20 @@ public class UserLifecycleTests { } @Test + public void createUser() { + while (mRunner.keepRunning()) { + final int userId = createUserNoFlags(); + + mRunner.pauseTiming(); + removeUser(userId); + mRunner.resumeTiming(); + } + } + + @Test public void createAndStartUser() throws Exception { while (mRunner.keepRunning()) { - final int userId = createUser(); + final int userId = createUserNoFlags(); final CountDownLatch latch = new CountDownLatch(1); registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId); @@ -140,7 +151,7 @@ public class UserLifecycleTests { while (mRunner.keepRunning()) { mRunner.pauseTiming(); final int startUser = mAm.getCurrentUser(); - final int userId = createUser(); + final int userId = createUserNoFlags(); mRunner.resumeTiming(); switchUser(userId); @@ -197,7 +208,7 @@ public class UserLifecycleTests { public void stopUser() throws Exception { while (mRunner.keepRunning()) { mRunner.pauseTiming(); - final int userId = createUser(); + final int userId = createUserNoFlags(); final CountDownLatch latch = new CountDownLatch(1); registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId); mIam.startUserInBackground(userId); @@ -217,7 +228,7 @@ public class UserLifecycleTests { while (mRunner.keepRunning()) { mRunner.pauseTiming(); final int startUser = mAm.getCurrentUser(); - final int userId = createUser(); + final int userId = createUserNoFlags(); final CountDownLatch latch = new CountDownLatch(1); registerUserSwitchObserver(null, latch, userId); mRunner.resumeTiming(); @@ -237,7 +248,7 @@ public class UserLifecycleTests { while (mRunner.keepRunning()) { mRunner.pauseTiming(); final int startUser = mAm.getCurrentUser(); - final int userId = createUser(UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO); + final int userId = createUserWithFlags(UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO); switchUser(userId); final CountDownLatch latch = new CountDownLatch(1); InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() { @@ -396,7 +407,6 @@ public class UserLifecycleTests { public void managedProfileCreateUnlockInstallAndLaunchApp() throws Exception { assumeTrue(mHasManagedUserFeature); - final String packageName = "perftests.multiuser.apps.dummyapp"; while (mRunner.keepRunning()) { mRunner.pauseTiming(); WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null); @@ -433,12 +443,12 @@ public class UserLifecycleTests { } /** Creates a new user, returning its userId. */ - private int createUser() { - return createUser(0); + private int createUserNoFlags() { + return createUserWithFlags(/* flags= */ 0); } /** Creates a new user with the given flags, returning its userId. */ - private int createUser(int flags) { + private int createUserWithFlags(int flags) { int userId = mUm.createUser("TestUser", flags).id; mUsersToRemove.add(userId); return userId; @@ -501,7 +511,7 @@ public class UserLifecycleTests { private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws Exception { final int origUser = mAm.getCurrentUser(); // First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED - final int testUser = createUser(); + final int testUser = createUserNoFlags(); final CountDownLatch latch1 = new CountDownLatch(1); registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, testUser); mAm.switchUser(testUser); diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index d0e38b4a4e36..65aaf20ecacb 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -67,6 +67,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.AtomicFile; import android.util.KeyValueListParser; import android.util.MutableLong; import android.util.Pair; @@ -79,7 +80,6 @@ import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; -import com.android.internal.os.AtomicFile; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; diff --git a/api/current.txt b/api/current.txt index 359ce3aa4373..26c90dff3c6b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5320,10 +5320,12 @@ package android.app { ctor public Notification(android.os.Parcel); method public android.app.Notification clone(); method public int describeContents(); + method @Nullable public android.util.Pair<android.app.RemoteInput,android.app.Notification.Action> findRemoteInputActionPair(boolean); method public boolean getAllowSystemGeneratedContextualActions(); method public int getBadgeIconType(); method @Nullable public android.app.Notification.BubbleMetadata getBubbleMetadata(); method public String getChannelId(); + method @NonNull public java.util.List<android.app.Notification.Action> getContextualActions(); method public String getGroup(); method public int getGroupAlertBehavior(); method public android.graphics.drawable.Icon getLargeIcon(); @@ -5719,6 +5721,7 @@ package android.app { method public String getDataMimeType(); method public android.net.Uri getDataUri(); method public android.os.Bundle getExtras(); + method @NonNull public static java.util.List<android.app.Notification.MessagingStyle.Message> getMessagesFromBundleArray(@Nullable android.os.Parcelable[]); method @Deprecated public CharSequence getSender(); method @Nullable public android.app.Person getSenderPerson(); method public CharSequence getText(); @@ -5816,6 +5819,7 @@ package android.app { method public android.net.Uri getSound(); method public long[] getVibrationPattern(); method public boolean hasUserSetImportance(); + method public boolean hasUserSetSound(); method public void setAllowBubbles(boolean); method public void setBypassDnd(boolean); method public void setDescription(String); @@ -41736,6 +41740,7 @@ package android.service.notification { method public int getUid(); method public android.os.UserHandle getUser(); method @Deprecated public int getUserId(); + method public boolean isAppGroup(); method public boolean isClearable(); method public boolean isGroup(); method public boolean isOngoing(); diff --git a/api/system-current.txt b/api/system-current.txt index 1c5f772f2e1b..8ee6e639cbe8 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -521,8 +521,6 @@ package android.app { } public class Notification implements android.os.Parcelable { - method @Nullable public android.util.Pair<android.app.RemoteInput,android.app.Notification.Action> findRemoteInputActionPair(boolean); - method @NonNull public java.util.List<android.app.Notification.Action> getContextualActions(); field public static final String CATEGORY_CAR_EMERGENCY = "car_emergency"; field public static final String CATEGORY_CAR_INFORMATION = "car_information"; field public static final String CATEGORY_CAR_WARNING = "car_warning"; @@ -531,10 +529,6 @@ package android.app { field public static final int FLAG_AUTOGROUP_SUMMARY = 1024; // 0x400 } - public static final class Notification.MessagingStyle.Message { - method @Nullable public static android.app.Notification.MessagingStyle.Message getMessageFromBundle(@NonNull android.os.Bundle); - } - public static final class Notification.TvExtender implements android.app.Notification.Extender { ctor public Notification.TvExtender(); ctor public Notification.TvExtender(android.app.Notification); @@ -6710,10 +6704,6 @@ package android.service.notification { field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.SnoozeCriterion> CREATOR; } - public class StatusBarNotification implements android.os.Parcelable { - method public boolean isAppGroup(); - } - } package android.service.oemlock { diff --git a/api/test-current.txt b/api/test-current.txt index 43b9086a8dec..6e28f67e9a68 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -97,8 +97,7 @@ package android.app { method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException; method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void removeStacksWithActivityTypes(int[]) throws java.lang.SecurityException; method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeDockedStack(android.graphics.Rect, android.graphics.Rect); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException; - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeStack(int, android.graphics.Rect, boolean); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizePinnedStack(int, android.graphics.Rect, boolean); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeTask(int, android.graphics.Rect); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setDisplayToSingleTaskInstance(int); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException; diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 19fa64073183..14f48711e068 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -65,7 +65,7 @@ cc_defaults { "src/condition/condition_util.cpp", "src/condition/SimpleConditionTracker.cpp", "src/condition/ConditionWizard.cpp", - "src/condition/StateTracker.cpp", + "src/condition/StateConditionTracker.cpp", "src/config/ConfigKey.cpp", "src/config/ConfigListener.cpp", "src/config/ConfigManager.cpp", @@ -227,7 +227,7 @@ cc_test { "tests/FieldValue_test.cpp", "tests/condition/CombinationConditionTracker_test.cpp", "tests/condition/SimpleConditionTracker_test.cpp", - "tests/condition/StateTracker_test.cpp", + "tests/condition/StateConditionTracker_test.cpp", "tests/condition/ConditionTimer_test.cpp", "tests/metrics/OringDurationTracker_test.cpp", "tests/metrics/MaxDurationTracker_test.cpp", diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 2c8a5562c979..ae751ce6d7ab 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -334,6 +334,7 @@ message Atom { BackGesture back_gesture_reported_reported = 224; UpdateEngineUpdateAttemptReported update_engine_update_attempt_reported = 225; UpdateEngineSuccessfulUpdateReported update_engine_successful_update_reported = 226; + CameraActionEvent camera_action_event = 227; } // Pulled events will start at field 10000. @@ -7164,3 +7165,29 @@ message FrameTimingHistogram { // It's required that len(time_millis) == len(frame_count) repeated int64 frame_counts = 2; } + + +/** + * Information about camera facing and API level usage. + * Logged from: + * frameworks/base/services/core/java/com/android/server/camera/CameraServiceProxy.java + */ +message CameraActionEvent { + // Camera session duration + optional int64 duration = 1; + + // Camera API level used + optional int32 api_level = 2; + + // Name of client package + optional string package_name = 3; + + // Camera facing + enum Facing { + UNKNOWN = 0; + BACK = 1; + FRONT = 2; + EXTERNAL = 3; + } + optional Facing facing = 4; +} diff --git a/cmds/statsd/src/condition/StateTracker.cpp b/cmds/statsd/src/condition/StateConditionTracker.cpp index 18c7178dd7d7..7f3eeddba831 100644 --- a/cmds/statsd/src/condition/StateTracker.cpp +++ b/cmds/statsd/src/condition/StateConditionTracker.cpp @@ -16,7 +16,7 @@ #define DEBUG false // STOPSHIP if true #include "Log.h" -#include "StateTracker.h" +#include "StateConditionTracker.h" #include "guardrail/StatsdStats.h" namespace android { @@ -27,7 +27,7 @@ using std::string; using std::unordered_set; using std::vector; -StateTracker::StateTracker(const ConfigKey& key, const int64_t& id, const int index, +StateConditionTracker::StateConditionTracker(const ConfigKey& key, const int64_t& id, const int index, const SimplePredicate& simplePredicate, const unordered_map<int64_t, int>& trackerNameIndexMap, const vector<Matcher> primaryKeys) @@ -69,19 +69,19 @@ StateTracker::StateTracker(const ConfigKey& key, const int64_t& id, const int in mInitialized = true; } -StateTracker::~StateTracker() { - VLOG("~StateTracker()"); +StateConditionTracker::~StateConditionTracker() { + VLOG("~StateConditionTracker()"); } -bool StateTracker::init(const vector<Predicate>& allConditionConfig, +bool StateConditionTracker::init(const vector<Predicate>& allConditionConfig, const vector<sp<ConditionTracker>>& allConditionTrackers, const unordered_map<int64_t, int>& conditionIdIndexMap, vector<bool>& stack) { return mInitialized; } -void StateTracker::dumpState() { - VLOG("StateTracker %lld DUMP:", (long long)mConditionId); +void StateConditionTracker::dumpState() { + VLOG("StateConditionTracker %lld DUMP:", (long long)mConditionId); for (const auto& value : mSlicedState) { VLOG("\t%s -> %s", value.first.toString().c_str(), value.second.toString().c_str()); } @@ -95,7 +95,7 @@ void StateTracker::dumpState() { } } -bool StateTracker::hitGuardRail(const HashableDimensionKey& newKey) { +bool StateConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) { if (mSlicedState.find(newKey) != mSlicedState.end()) { // if the condition is not sliced or the key is not new, we are good! return false; @@ -114,7 +114,7 @@ bool StateTracker::hitGuardRail(const HashableDimensionKey& newKey) { return false; } -void StateTracker::evaluateCondition(const LogEvent& event, +void StateConditionTracker::evaluateCondition(const LogEvent& event, const vector<MatchingState>& eventMatcherValues, const vector<sp<ConditionTracker>>& mAllConditions, vector<ConditionState>& conditionCache, @@ -135,7 +135,7 @@ void StateTracker::evaluateCondition(const LogEvent& event, return; } - VLOG("StateTracker evaluate event %s", event.ToString().c_str()); + VLOG("StateConditionTracker evaluate event %s", event.ToString().c_str()); // Primary key can exclusive fields must be simple fields. so there won't be more than // one keys matched. @@ -151,7 +151,7 @@ void StateTracker::evaluateCondition(const LogEvent& event, } hitGuardRail(primaryKey); - VLOG("StateTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str()); + VLOG("StateConditionTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str()); auto it = mSlicedState.find(primaryKey); if (it == mSlicedState.end()) { @@ -176,7 +176,7 @@ void StateTracker::evaluateCondition(const LogEvent& event, return; } -void StateTracker::isConditionMet( +void StateConditionTracker::isConditionMet( const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions, const bool isPartialLink, vector<ConditionState>& conditionCache) const { diff --git a/cmds/statsd/src/condition/StateTracker.h b/cmds/statsd/src/condition/StateConditionTracker.h index 5ae4441713cd..0efe1fb3fcb2 100644 --- a/cmds/statsd/src/condition/StateTracker.h +++ b/cmds/statsd/src/condition/StateConditionTracker.h @@ -25,14 +25,14 @@ namespace android { namespace os { namespace statsd { -class StateTracker : public virtual ConditionTracker { +class StateConditionTracker : public virtual ConditionTracker { public: - StateTracker(const ConfigKey& key, const int64_t& id, const int index, + StateConditionTracker(const ConfigKey& key, const int64_t& id, const int index, const SimplePredicate& simplePredicate, const std::unordered_map<int64_t, int>& trackerNameIndexMap, const vector<Matcher> primaryKeys); - ~StateTracker(); + ~StateConditionTracker(); bool init(const std::vector<Predicate>& allConditionConfig, const std::vector<sp<ConditionTracker>>& allConditionTrackers, @@ -46,8 +46,8 @@ public: std::vector<bool>& changedCache) override; /** - * Note: dimensionFields will be ignored in StateTracker, because we demand metrics - * must take the entire dimension fields from StateTracker. This is to make implementation + * Note: dimensionFields will be ignored in StateConditionTracker, because we demand metrics + * must take the entire dimension fields from StateConditionTracker. This is to make implementation * simple and efficient. * * For example: wakelock duration by uid process states: @@ -109,7 +109,7 @@ private: // maps from [primary_key] to [primary_key, exclusive_state]. std::unordered_map<HashableDimensionKey, HashableDimensionKey> mSlicedState; - FRIEND_TEST(StateTrackerTest, TestStateChange); + FRIEND_TEST(StateConditionTrackerTest, TestStateChange); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index dd32c08faba3..111b4346151a 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -21,7 +21,7 @@ #include "../condition/CombinationConditionTracker.h" #include "../condition/SimpleConditionTracker.h" -#include "../condition/StateTracker.h" +#include "../condition/StateConditionTracker.h" #include "../external/StatsPullerManager.h" #include "../matchers/CombinationLogMatchingTracker.h" #include "../matchers/SimpleLogMatchingTracker.h" @@ -182,13 +182,13 @@ bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap, } /** - * A StateTracker is built from a SimplePredicate which has only "start", and no "stop" + * A StateConditionTracker is built from a SimplePredicate which has only "start", and no "stop" * or "stop_all". The start must be an atom matcher that matches a state atom. It must * have dimension, the dimension must be the state atom's primary fields plus exclusive state - * field. For example, the StateTracker is used in tracking UidProcessState and ScreenState. + * field. For example, the StateConditionTracker is used in tracking UidProcessState and ScreenState. * */ -bool isStateTracker(const SimplePredicate& simplePredicate, vector<Matcher>* primaryKeys) { +bool isStateConditionTracker(const SimplePredicate& simplePredicate, vector<Matcher>* primaryKeys) { // 1. must not have "stop". must have "dimension" if (!simplePredicate.has_stop() && simplePredicate.has_dimensions()) { auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find( @@ -240,8 +240,8 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config, switch (condition.contents_case()) { case Predicate::ContentsCase::kSimplePredicate: { vector<Matcher> primaryKeys; - if (isStateTracker(condition.simple_predicate(), &primaryKeys)) { - allConditionTrackers.push_back(new StateTracker(key, condition.id(), index, + if (isStateConditionTracker(condition.simple_predicate(), &primaryKeys)) { + allConditionTrackers.push_back(new StateConditionTracker(key, condition.id(), index, condition.simple_predicate(), logTrackerMap, primaryKeys)); } else { diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h index 028231ff908c..3704969039c4 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/metrics_manager_util.h @@ -113,7 +113,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& vector<int>& metricsWithActivation, std::set<int64_t>& noReportMetricIds); -bool isStateTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys); +bool isStateConditionTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys); } // namespace statsd } // namespace os diff --git a/cmds/statsd/tests/condition/StateTracker_test.cpp b/cmds/statsd/tests/condition/StateConditionTracker_test.cpp index 9a66254afce0..fbf6efdcf966 100644 --- a/cmds/statsd/tests/condition/StateTracker_test.cpp +++ b/cmds/statsd/tests/condition/StateConditionTracker_test.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "src/condition/StateTracker.h" +#include "src/condition/StateConditionTracker.h" #include "tests/statsd_test_util.h" #include <gmock/gmock.h> @@ -50,7 +50,7 @@ void makeUidProcStateEvent(int32_t uid, int32_t state, LogEvent* event) { event->init(); } -TEST(StateTrackerTest, TestStateChange) { +TEST(StateConditionTrackerTest, TestStateChange) { int uid1 = 111; int uid2 = 222; @@ -60,7 +60,7 @@ TEST(StateTrackerTest, TestStateChange) { trackerNameIndexMap[StringToId("UidProcState")] = 0; vector<Matcher> primaryFields; primaryFields.push_back(getSimpleMatcher(kUidProcTag, 1)); - StateTracker tracker(ConfigKey(12, 123), 123, 0, getUidProcStatePredicate(), + StateConditionTracker tracker(ConfigKey(12, 123), 123, 0, getUidProcStatePredicate(), trackerNameIndexMap, primaryFields); LogEvent event(kUidProcTag, 0 /*timestamp*/); diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java index 4ef554dc64cc..ac8c9f466f33 100644 --- a/core/java/android/app/ActivityTaskManager.java +++ b/core/java/android/app/ActivityTaskManager.java @@ -202,21 +202,6 @@ public class ActivityTaskManager { } /** - * Resizes the input stack id to the given bounds. - * @param stackId Id of the stack to resize. - * @param bounds Bounds to resize the stack to or {@code null} for fullscreen. - */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - public void resizeStack(int stackId, Rect bounds) throws SecurityException { - try { - getService().resizeStack(stackId, bounds, false /* allowResizeInDockedMode */, - false /* preserveWindows */, false /* animate */, -1 /* animationDuration */); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Removes stacks in the windowing modes from the system if they are of activity type * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED */ @@ -362,10 +347,13 @@ public class ActivityTaskManager { * @param animate Whether we should play an animation for resizing stack. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - public void resizeStack(int stackId, Rect bounds, boolean animate) { + public void resizePinnedStack(int stackId, Rect bounds, boolean animate) { try { - getService().resizeStack(stackId, bounds, false, false, animate /* animate */, - -1 /* animationDuration */); + if (animate) { + getService().animateResizePinnedStack(stackId, bounds, -1 /* animationDuration */); + } else { + getService().resizePinnedStack(bounds, null /* tempPinnedTaskBounds */); + } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index dbe50c3d24a0..dca00a2bbd83 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -406,23 +406,6 @@ interface IActivityManager { List<ActivityManager.StackInfo> getAllStackInfos(); @UnsupportedAppUsage void moveTaskToStack(int taskId, int stackId, boolean toTop); - /** - * Resizes the input stack id to the given bounds. - * - * @param stackId Id of the stack to resize. - * @param bounds Bounds to resize the stack to or {@code null} for fullscreen. - * @param allowResizeInDockedMode True if the resize should be allowed when the docked stack is - * active. - * @param preserveWindows True if the windows of activities contained in the stack should be - * preserved. - * @param animate True if the stack resize should be animated. - * @param animationDuration The duration of the resize animation in milliseconds or -1 if the - * default animation duration should be used. - * @throws RemoteException - */ - @UnsupportedAppUsage - void resizeStack(int stackId, in Rect bounds, boolean allowResizeInDockedMode, - boolean preserveWindows, boolean animate, int animationDuration); void setFocusedStack(int stackId); ActivityManager.StackInfo getFocusedStackInfo(); @UnsupportedAppUsage diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index 47b784b3eaaf..dda3bb53ebe3 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -234,21 +234,15 @@ interface IActivityTaskManager { void setTaskWindowingMode(int taskId, int windowingMode, boolean toTop); void moveTaskToStack(int taskId, int stackId, boolean toTop); /** - * Resizes the input stack id to the given bounds. + * Resizes the input pinned stack to the given bounds with animation. * - * @param stackId Id of the stack to resize. + * @param stackId Id of the pinned stack to resize. * @param bounds Bounds to resize the stack to or {@code null} for fullscreen. - * @param allowResizeInDockedMode True if the resize should be allowed when the docked stack is - * active. - * @param preserveWindows True if the windows of activities contained in the stack should be - * preserved. - * @param animate True if the stack resize should be animated. * @param animationDuration The duration of the resize animation in milliseconds or -1 if the * default animation duration should be used. * @throws RemoteException */ - void resizeStack(int stackId, in Rect bounds, boolean allowResizeInDockedMode, - boolean preserveWindows, boolean animate, int animationDuration); + void animateResizePinnedStack(int stackId, in Rect bounds, int animationDuration); boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop, boolean animate, in Rect initialBounds, boolean showRecents); /** diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index f065ff791dce..bb4e99873f26 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -3274,11 +3274,8 @@ public class Notification implements Parcelable * * @param requiresFreeform requires the remoteinput to allow freeform or not. * @return the result pair, {@code null} if no result is found. - * - * @hide */ @Nullable - @SystemApi public Pair<RemoteInput, Action> findRemoteInputActionPair(boolean requiresFreeform) { if (actions == null) { return null; @@ -3301,11 +3298,9 @@ public class Notification implements Parcelable } /** - * Returns the actions that are contextual out of the actions in this notification. - * - * @hide + * Returns the actions that are contextual (that is, suggested because of the content of the + * notification) out of the actions in this notification. */ - @SystemApi public @NonNull List<Notification.Action> getContextualActions() { if (actions == null) return Collections.emptyList(); @@ -7705,11 +7700,11 @@ public class Notification implements Parcelable } /** - * @return A list of messages read from the bundles. - * - * @hide + * Returns a list of messages read from the given bundle list, e.g. + * {@link #EXTRA_MESSAGES} or {@link #EXTRA_HISTORIC_MESSAGES}. */ - public static List<Message> getMessagesFromBundleArray(Parcelable[] bundles) { + @NonNull + public static List<Message> getMessagesFromBundleArray(@Nullable Parcelable[] bundles) { if (bundles == null) { return new ArrayList<>(); } @@ -7726,13 +7721,12 @@ public class Notification implements Parcelable } /** - * @return The message that is stored in the bundle or null if the message couldn't be - * resolved. - * + * Returns the message that is stored in the bundle (e.g. one of the values in the lists + * in {@link #EXTRA_MESSAGES} or {@link #EXTRA_HISTORIC_MESSAGES}) or null if the + * message couldn't be resolved. * @hide */ @Nullable - @SystemApi public static Message getMessageFromBundle(@NonNull Bundle bundle) { try { if (!bundle.containsKey(KEY_TEXT) || !bundle.containsKey(KEY_TIMESTAMP)) { diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 93e4ddcbb016..20d977b7da10 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -710,6 +710,14 @@ public final class NotificationChannel implements Parcelable { } /** + * Returns whether the user has chosen the sound of this channel. + * @see #getSound() + */ + public boolean hasUserSetSound() { + return (mUserLockedFields & USER_LOCKED_SOUND) != 0; + } + + /** * @hide */ public void populateFromXmlForRestore(XmlPullParser parser, Context context) { diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java index 205df7e12483..b8378a3474ac 100644 --- a/core/java/android/service/notification/StatusBarNotification.java +++ b/core/java/android/service/notification/StatusBarNotification.java @@ -170,10 +170,7 @@ public class StatusBarNotification implements Parcelable { /** * Returns true if application asked that this notification be part of a group. - * - * @hide */ - @SystemApi public boolean isAppGroup() { if (getNotification().getGroup() != null || getNotification().getSortKey() != null) { return true; diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index bfab580ea077..937990f7e88e 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -1639,7 +1639,7 @@ public class ZenModeConfig implements Parcelable { @UnsupportedAppUsage public String name; // required for automatic @UnsupportedAppUsage - public int zenMode; + public int zenMode; // ie: Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS @UnsupportedAppUsage public Uri conditionId; // required for automatic public Condition condition; // optional diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index a52a7ed982ec..4cb2d1502610 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -658,6 +658,12 @@ static jlong android_os_Process_getTotalMemory(JNIEnv* env, jobject clazz) return si.totalram; } +/* + * The outFields array is initialized to -1 to allow the caller to identify + * when the status file (and therefore the process) they specified is invalid. + * This array should not be overwritten or cleared before we know that the + * status file can be read. + */ void android_os_Process_readProcLines(JNIEnv* env, jobject clazz, jstring fileStr, jobjectArray reqFields, jlongArray outFields) { @@ -706,14 +712,14 @@ void android_os_Process_readProcLines(JNIEnv* env, jobject clazz, jstring fileSt return; } - //ALOGI("Clearing %" PRId32 " sizes", count); - for (i=0; i<count; i++) { - sizesArray[i] = 0; - } - int fd = open(file.string(), O_RDONLY | O_CLOEXEC); if (fd >= 0) { + //ALOGI("Clearing %" PRId32 " sizes", count); + for (i=0; i<count; i++) { + sizesArray[i] = 0; + } + const size_t BUFFER_SIZE = 4096; char* buffer = (char*)malloc(BUFFER_SIZE); int len = read(fd, buffer, BUFFER_SIZE-1); diff --git a/core/tests/coretests/src/android/os/ProcessTest.java b/core/tests/coretests/src/android/os/ProcessTest.java index 9de450196fa0..ae4edb97aab0 100644 --- a/core/tests/coretests/src/android/os/ProcessTest.java +++ b/core/tests/coretests/src/android/os/ProcessTest.java @@ -17,13 +17,12 @@ package android.os; -import androidx.test.filters.MediumTest; - import junit.framework.TestCase; public class ProcessTest extends TestCase { - @MediumTest + private static final int BAD_PID = 0; + public void testProcessGetUidFromName() throws Exception { assertEquals(android.os.Process.SYSTEM_UID, Process.getUidForName("system")); assertEquals(Process.BLUETOOTH_UID, Process.getUidForName("bluetooth")); @@ -37,7 +36,6 @@ public class ProcessTest extends TestCase { Process.getUidForName("u3_a100")); } - @MediumTest public void testProcessGetUidFromNameFailure() throws Exception { // Failure cases assertEquals(-1, Process.getUidForName("u2a_foo")); @@ -49,4 +47,29 @@ public class ProcessTest extends TestCase { assertEquals(-1, Process.getUidForName("u2jhsajhfkjhsafkhskafhkashfkjashfkjhaskjfdhakj3")); } + /** + * Tests getUidForPid() by ensuring that it returns the correct value when the process queried + * doesn't exist. + */ + public void testGetUidForPidInvalidPid() { + assertEquals(-1, Process.getUidForPid(BAD_PID)); + } + + /** + * Tests getParentPid() by ensuring that it returns the correct value when the process queried + * doesn't exist. + */ + public void testGetParentPidInvalidPid() { + assertEquals(-1, Process.getParentPid(BAD_PID)); + } + + /** + * Tests getThreadGroupLeader() by ensuring that it returns the correct value when the + * thread queried doesn't exist. + */ + public void testGetThreadGroupLeaderInvalidTid() { + // This function takes a TID instead of a PID but BAD_PID should also be a bad TID. + assertEquals(-1, Process.getThreadGroupLeader(BAD_PID)); + } + } diff --git a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java index 6161108d4d70..a5a98a98f0be 100644 --- a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java +++ b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java @@ -19,6 +19,8 @@ package android.service.notification; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -181,6 +183,22 @@ public class StatusBarNotificationTest { logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_STYLE)); } + @Test + public void testIsAppGroup() { + StatusBarNotification sbn = getNotification(PKG, GROUP_ID_1, CHANNEL_ID); + assertTrue(sbn.isAppGroup()); + + sbn = getNotification(PKG, null, CHANNEL_ID); + assertFalse(sbn.isAppGroup()); + + Notification.Builder nb = getNotificationBuilder(null, CHANNEL_ID) + .setSortKey("something"); + + sbn = getNotification(PKG, nb); + assertTrue(sbn.isAppGroup()); + + } + private StatusBarNotification getNotification(String pkg, String group, String channelId) { return getNotification(pkg, getNotificationBuilder(group, channelId)); } diff --git a/packages/CarSystemUI/res/values/integers_car.xml b/packages/CarSystemUI/res/values/integers_car.xml index 862ba751aa55..fb67b302a4ae 100644 --- a/packages/CarSystemUI/res/values/integers_car.xml +++ b/packages/CarSystemUI/res/values/integers_car.xml @@ -32,6 +32,6 @@ at will result in remaining closed the panel if released--> <integer name="notification_settle_close_percentage">80</integer> <!-- The delay before the unlock dialog pops up --> - <integer name="unlock_dialog_delay_ms">3000</integer> + <integer name="unlock_dialog_delay_ms">0</integer> </resources> diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java index d6b766b80939..27146fbac789 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java @@ -26,6 +26,7 @@ import dagger.Component; DependencyProvider.class, DependencyBinder.class, ServiceBinder.class, + SystemUIBinder.class, SystemUIFactory.ContextHolder.class, SystemUIModule.class, CarSystemUIModule.class diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml index aed200f69bc3..925e4fad103d 100644 --- a/packages/SystemUI/res/layout/auth_biometric_contents.xml +++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml @@ -56,7 +56,7 @@ android:scaleType="fitXY" /> <TextView - android:id="@+id/error" + android:id="@+id/indicator" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingHorizontal="24dp" diff --git a/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java b/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java index 62826d806adc..5fe5792219c3 100644 --- a/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java +++ b/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java @@ -24,4 +24,7 @@ import android.app.Service; public interface ContextComponentHelper { /** Turns a classname into an instance of the class or returns null. */ Service resolveService(String className); + + /** Turns a classname into an instance of the class or returns null. */ + SystemUI resolveSystemUI(String className); } diff --git a/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java b/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java index e8f019688997..cee21c167fa0 100644 --- a/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java +++ b/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java @@ -22,17 +22,22 @@ import java.util.Map; import javax.inject.Inject; import javax.inject.Provider; +import javax.inject.Singleton; /** * Used during Service and Activity instantiation to make them injectable. */ +@Singleton public class ContextComponentResolver implements ContextComponentHelper { private final Map<Class<?>, Provider<Service>> mServiceCreators; + private final Map<Class<?>, Provider<SystemUI>> mSystemUICreators; @Inject ContextComponentResolver( - Map<Class<?>, Provider<Service>> serviceCreators) { + Map<Class<?>, Provider<Service>> serviceCreators, + Map<Class<?>, Provider<SystemUI>> systemUICreators) { mServiceCreators = serviceCreators; + mSystemUICreators = systemUICreators; } /** @@ -43,6 +48,14 @@ public class ContextComponentResolver implements ContextComponentHelper { return resolve(className, mServiceCreators); } + /** + * Looks up the SystemUI class name to see if Dagger has an instance of it. + */ + @Override + public SystemUI resolveSystemUI(String className) { + return resolve(className, mSystemUICreators); + } + private <T> T resolve(String className, Map<Class<?>, Provider<T>> creators) { for (Map.Entry<Class<?>, Provider<T>> p : creators.entrySet()) { if (p.getKey().getName().equals(className)) { diff --git a/packages/SystemUI/src/com/android/systemui/SystemUI.java b/packages/SystemUI/src/com/android/systemui/SystemUI.java index 78a12467cd1c..30fbef6cbefb 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUI.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUI.java @@ -24,7 +24,6 @@ import android.os.Bundle; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Map; -import java.util.function.Function; public abstract class SystemUI implements SysUiServiceProvider { public Context mContext; @@ -62,7 +61,4 @@ public abstract class SystemUI implements SysUiServiceProvider { n.addExtras(extras); } - - public interface Injector extends Function<Context, SystemUI> { - } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 1c210b177ae7..56b5d080acc0 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -54,6 +54,8 @@ public class SystemUIApplication extends Application implements SysUiServiceProv public static final String TAG = "SystemUIService"; private static final boolean DEBUG = false; + private ContextComponentHelper mComponentHelper; + /** * Hold a reference on the stuff we start. */ @@ -78,6 +80,8 @@ public class SystemUIApplication extends Application implements SysUiServiceProv Trace.TRACE_TAG_APP); log.traceBegin("DependencyInjection"); mContextAvailableCallback.onContextAvailable(this); + mComponentHelper = SystemUIFactory + .getInstance().getRootComponent().getContextComponentHelper(); log.traceEnd(); // Set the application theme that is inherited by all services. Note that setting the @@ -186,14 +190,12 @@ public class SystemUIApplication extends Application implements SysUiServiceProv if (DEBUG) Log.d(TAG, "loading: " + clsName); log.traceBegin("StartServices" + clsName); long ti = System.currentTimeMillis(); - Class cls; try { - cls = Class.forName(clsName); - Object o = cls.newInstance(); - if (o instanceof SystemUI.Injector) { - o = ((SystemUI.Injector) o).apply(this); + SystemUI obj = mComponentHelper.resolveSystemUI(clsName); + if (obj == null) { + obj = (SystemUI) Class.forName(clsName).newInstance(); } - mServices[i] = (SystemUI) o; + mServices[i] = obj; } catch (ClassNotFoundException ex) { throw new RuntimeException(ex); } catch (IllegalAccessException ex) { @@ -211,7 +213,7 @@ public class SystemUIApplication extends Application implements SysUiServiceProv // Warn if initialization of component takes too long ti = System.currentTimeMillis() - ti; if (ti > 1000) { - Log.w(TAG, "Initialization of " + cls.getName() + " took " + ti + " ms"); + Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms"); } if (mBootCompleted) { mServices[i].onBootCompleted(); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java new file mode 100644 index 000000000000..88d659039b4b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui; + +import com.android.systemui.keyguard.KeyguardViewMediator; + +import dagger.Binds; +import dagger.Module; +import dagger.multibindings.ClassKey; +import dagger.multibindings.IntoMap; + +/** + * Services and Activities that are injectable should go here. + */ +@Module +public abstract class SystemUIBinder { + /** Inject into KeyguardViewMediator. */ + @Binds + @IntoMap + @ClassKey(KeyguardViewMediator.class) + public abstract SystemUI bindKeyguardViewMediator(KeyguardViewMediator sysui); +} diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java index b77667e339af..6ce673b0e9b6 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java @@ -38,10 +38,18 @@ import dagger.Component; DependencyProvider.class, DependencyBinder.class, ServiceBinder.class, + SystemUIBinder.class, SystemUIFactory.ContextHolder.class, SystemUIModule.class, SystemUIDefaultModule.class}) public interface SystemUIRootComponent { + + /** + * Creates a GarbageMonitor. + */ + @Singleton + ContextComponentHelper getContextComponentHelper(); + /** * Main dependency providing module. */ @@ -66,7 +74,7 @@ public interface SystemUIRootComponent { InjectionInflationController.ViewCreator createViewCreator(); /** - * Creatse a GarbageMonitor. + * Creates a GarbageMonitor. */ @Singleton GarbageMonitor createGarbageMonitor(); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java index 74cc9c39741e..a68b61e4da45 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java @@ -154,18 +154,18 @@ public class AuthBiometricFaceView extends AuthBiometricView { @Override protected void handleResetAfterError() { - resetErrorView(mContext, mErrorView); + resetErrorView(mContext, mIndicatorView); } @Override protected void handleResetAfterHelp() { - resetErrorView(mContext, mErrorView); + resetErrorView(mContext, mIndicatorView); } @Override protected void onFinishInflate() { super.onFinishInflate(); - mIconController = new IconController(mContext, mIconView, mErrorView); + mIconController = new IconController(mContext, mIconView, mIndicatorView); } @Override @@ -174,7 +174,7 @@ public class AuthBiometricFaceView extends AuthBiometricView { if (newState == STATE_AUTHENTICATING_ANIMATING_IN || (newState == STATE_AUTHENTICATING && mSize == AuthDialog.SIZE_MEDIUM)) { - resetErrorView(mContext, mErrorView); + resetErrorView(mContext, mIndicatorView); } // Do this last since the state variable gets updated. diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java index f26083998c76..df14a1716571 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java @@ -21,6 +21,8 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.BiometricPrompt; import android.os.Bundle; @@ -127,8 +129,8 @@ public abstract class AuthBiometricView extends LinearLayout { return mBiometricView.findViewById(R.id.description); } - public TextView getErrorView() { - return mBiometricView.findViewById(R.id.error); + public TextView getIndicatorView() { + return mBiometricView.findViewById(R.id.indicator); } public ImageView getIconView() { @@ -150,7 +152,7 @@ public abstract class AuthBiometricView extends LinearLayout { private TextView mSubtitleView; private TextView mDescriptionView; protected ImageView mIconView; - @VisibleForTesting protected TextView mErrorView; + @VisibleForTesting protected TextView mIndicatorView; @VisibleForTesting Button mNegativeButton; @VisibleForTesting Button mPositiveButton; @VisibleForTesting Button mTryAgainButton; @@ -165,6 +167,7 @@ public abstract class AuthBiometricView extends LinearLayout { private float mIconOriginalY; protected boolean mDialogSizeAnimating; + protected Bundle mSavedState; /** * Delay after authentication is confirmed, before the dialog should be animated away. @@ -252,7 +255,7 @@ public abstract class AuthBiometricView extends LinearLayout { mTitleView.setVisibility(View.GONE); mSubtitleView.setVisibility(View.GONE); mDescriptionView.setVisibility(View.GONE); - mErrorView.setVisibility(View.GONE); + mIndicatorView.setVisibility(View.GONE); mNegativeButton.setVisibility(View.GONE); final float iconPadding = getResources() @@ -284,7 +287,7 @@ public abstract class AuthBiometricView extends LinearLayout { final float opacity = (float) animation.getAnimatedValue(); mTitleView.setAlpha(opacity); - mErrorView.setAlpha(opacity); + mIndicatorView.setAlpha(opacity); mNegativeButton.setAlpha(opacity); mTryAgainButton.setAlpha(opacity); @@ -304,7 +307,7 @@ public abstract class AuthBiometricView extends LinearLayout { public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); mTitleView.setVisibility(View.VISIBLE); - mErrorView.setVisibility(View.VISIBLE); + mIndicatorView.setVisibility(View.VISIBLE); mNegativeButton.setVisibility(View.VISIBLE); mTryAgainButton.setVisibility(View.VISIBLE); @@ -339,6 +342,7 @@ public abstract class AuthBiometricView extends LinearLayout { public void updateState(@BiometricState int newState) { Log.v(TAG, "newState: " + newState); + switch (newState) { case STATE_AUTHENTICATING_ANIMATING_IN: case STATE_AUTHENTICATING: @@ -353,7 +357,7 @@ public abstract class AuthBiometricView extends LinearLayout { if (mSize != AuthDialog.SIZE_SMALL) { mPositiveButton.setVisibility(View.GONE); mNegativeButton.setVisibility(View.GONE); - mErrorView.setVisibility(View.INVISIBLE); + mIndicatorView.setVisibility(View.INVISIBLE); } mHandler.postDelayed(() -> mCallback.onAction(Callback.ACTION_AUTHENTICATED), getDelayAfterAuthenticatedDurationMs()); @@ -364,9 +368,10 @@ public abstract class AuthBiometricView extends LinearLayout { mNegativeButton.setText(R.string.cancel); mNegativeButton.setContentDescription(getResources().getString(R.string.cancel)); mPositiveButton.setEnabled(true); - mErrorView.setTextColor(mTextColorHint); - mErrorView.setText(R.string.biometric_dialog_tap_confirm); - mErrorView.setVisibility(View.VISIBLE); + mPositiveButton.setVisibility(View.VISIBLE); + mIndicatorView.setTextColor(mTextColorHint); + mIndicatorView.setText(R.string.biometric_dialog_tap_confirm); + mIndicatorView.setVisibility(View.VISIBLE); break; case STATE_ERROR: @@ -409,6 +414,27 @@ public abstract class AuthBiometricView extends LinearLayout { updateState(STATE_HELP); } + public void onSaveState(@NonNull Bundle outState) { + outState.putInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY, + mTryAgainButton.getVisibility()); + outState.putInt(AuthDialog.KEY_BIOMETRIC_STATE, mState); + outState.putString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING, + mIndicatorView.getText().toString()); + outState.putBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING, + mHandler.hasCallbacks(mResetErrorRunnable)); + outState.putBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_HELP_SHOWING, + mHandler.hasCallbacks(mResetHelpRunnable)); + outState.putInt(AuthDialog.KEY_BIOMETRIC_DIALOG_SIZE, mSize); + } + + /** + * Invoked after inflation but before being attached to window. + * @param savedState + */ + public void restoreState(@Nullable Bundle savedState) { + mSavedState = savedState; + } + private void setTextOrHide(TextView view, String string) { if (TextUtils.isEmpty(string)) { view.setVisibility(View.GONE); @@ -429,25 +455,28 @@ public abstract class AuthBiometricView extends LinearLayout { private void showTemporaryMessage(String message, Runnable resetMessageRunnable) { removePendingAnimations(); - mErrorView.setText(message); - mErrorView.setTextColor(mTextColorError); - mErrorView.setVisibility(View.VISIBLE); + mIndicatorView.setText(message); + mIndicatorView.setTextColor(mTextColorError); + mIndicatorView.setVisibility(View.VISIBLE); mHandler.postDelayed(resetMessageRunnable, BiometricPrompt.HIDE_DIALOG_DELAY); } @Override protected void onFinishInflate() { super.onFinishInflate(); - initializeViews(); + onFinishInflateInternal(); } + /** + * After inflation, but before things like restoreState, onAttachedToWindow, etc. + */ @VisibleForTesting - void initializeViews() { + void onFinishInflateInternal() { mTitleView = mInjector.getTitleView(); mSubtitleView = mInjector.getSubtitleView(); mDescriptionView = mInjector.getDescriptionView(); mIconView = mInjector.getIconView(); - mErrorView = mInjector.getErrorView(); + mIndicatorView = mInjector.getIndicatorView(); mNegativeButton = mInjector.getNegativeButton(); mPositiveButton = mInjector.getPositiveButton(); mTryAgainButton = mInjector.getTryAgainButton(); @@ -474,13 +503,49 @@ public abstract class AuthBiometricView extends LinearLayout { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + onAttachedToWindowInternal(); + } + + /** + * Contains all the testable logic that should be invoked when {@link #onAttachedToWindow()} is + * invoked. + */ + @VisibleForTesting + void onAttachedToWindowInternal() { setText(mTitleView, mBundle.getString(BiometricPrompt.KEY_TITLE)); setText(mNegativeButton, mBundle.getString(BiometricPrompt.KEY_NEGATIVE_TEXT)); setTextOrHide(mSubtitleView, mBundle.getString(BiometricPrompt.KEY_SUBTITLE)); setTextOrHide(mDescriptionView, mBundle.getString(BiometricPrompt.KEY_DESCRIPTION)); - updateState(STATE_AUTHENTICATING_ANIMATING_IN); + if (mSavedState == null) { + updateState(STATE_AUTHENTICATING_ANIMATING_IN); + } else { + // Restore as much state as possible first + updateState(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_STATE)); + + // Restore positive button state + mTryAgainButton.setVisibility( + mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY)); + + // Restore indicator text state + final String indicatorText = + mSavedState.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING); + if (mSavedState.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_HELP_SHOWING)) { + onHelp(indicatorText); + } else if (mSavedState.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING)) { + onAuthenticationFailed(indicatorText); + } + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + // Empty the handler, otherwise things like ACTION_AUTHENTICATED may be duplicated once + // the new dialog is restored. + mHandler.removeCallbacksAndMessages(null /* all */); } @Override @@ -521,13 +586,24 @@ public abstract class AuthBiometricView extends LinearLayout { @Override public void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); + onLayoutInternal(); + } + /** + * Contains all the testable logic that should be invoked when + * {@link #onLayout(boolean, int, int, int, int)}, is invoked. + */ + @VisibleForTesting + void onLayoutInternal() { // Start with initial size only once. Subsequent layout changes don't matter since we // only care about the initial icon position. if (mIconOriginalY == 0) { mIconOriginalY = mIconView.getY(); - updateSize(mRequireConfirmation ? AuthDialog.SIZE_MEDIUM - : AuthDialog.SIZE_SMALL); + if (mSavedState == null) { + updateSize(mRequireConfirmation ? AuthDialog.SIZE_MEDIUM : AuthDialog.SIZE_SMALL); + } else { + updateSize(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_DIALOG_SIZE)); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 9cb5fcf4de00..e198060da9aa 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -17,6 +17,8 @@ package com.android.systemui.biometrics; import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.graphics.PixelFormat; import android.os.Binder; @@ -269,7 +271,8 @@ public class AuthContainerView extends LinearLayout } @Override - public void show(WindowManager wm) { + public void show(WindowManager wm, @Nullable Bundle savedState) { + mBiometricView.restoreState(savedState); wm.addView(this, getLayoutParams(mWindowToken)); } @@ -308,13 +311,8 @@ public class AuthContainerView extends LinearLayout } @Override - public void onSaveState(Bundle outState) { - - } - - @Override - public void restoreState(Bundle savedState) { - + public void onSaveState(@NonNull Bundle outState) { + mBiometricView.onSaveState(outState); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index dcd01c682726..ab89034c3b65 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -272,11 +272,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, + " type: " + type); } - if (savedState != null) { - // SavedState is only non-null if it's from onConfigurationChanged. Restore the state - // even though it may be removed / re-created again - newDialog.restoreState(savedState); - } else if (mCurrentDialog != null) { + if (mCurrentDialog != null) { // If somehow we're asked to show a dialog, the old one doesn't need to be animated // away. This can happen if the app cancels and re-starts auth during configuration // change. This is ugly because we also have to do things on onConfigurationChanged @@ -286,7 +282,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mReceiver = (IBiometricServiceReceiverInternal) args.arg2; mCurrentDialog = newDialog; - mCurrentDialog.show(mWindowManager); + mCurrentDialog.show(mWindowManager, savedState); } private void onDialogDismissed(@DismissedReason int reason) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java index a6a857ca5945..fb904231c175 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java @@ -17,7 +17,8 @@ package com.android.systemui.biometrics; import android.annotation.IntDef; -import android.hardware.biometrics.BiometricPrompt; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Bundle; import android.view.WindowManager; @@ -28,28 +29,12 @@ import java.lang.annotation.RetentionPolicy; * Interface for the biometric dialog UI. */ public interface AuthDialog { - - // TODO: Clean up save/restore state - String[] KEYS_TO_BACKUP = { - BiometricPrompt.KEY_TITLE, - BiometricPrompt.KEY_USE_DEFAULT_TITLE, - BiometricPrompt.KEY_SUBTITLE, - BiometricPrompt.KEY_DESCRIPTION, - BiometricPrompt.KEY_POSITIVE_TEXT, - BiometricPrompt.KEY_NEGATIVE_TEXT, - BiometricPrompt.KEY_REQUIRE_CONFIRMATION, - BiometricPrompt.KEY_ALLOW_DEVICE_CREDENTIAL, - BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, - - BiometricDialogView.KEY_TRY_AGAIN_VISIBILITY, - BiometricDialogView.KEY_CONFIRM_VISIBILITY, - BiometricDialogView.KEY_CONFIRM_ENABLED, - BiometricDialogView.KEY_STATE, - BiometricDialogView.KEY_ERROR_TEXT_VISIBILITY, - BiometricDialogView.KEY_ERROR_TEXT_STRING, - BiometricDialogView.KEY_ERROR_TEXT_IS_TEMPORARY, - BiometricDialogView.KEY_ERROR_TEXT_COLOR, - }; + String KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY = "try_agian_visibility"; + String KEY_BIOMETRIC_STATE = "state"; + String KEY_BIOMETRIC_INDICATOR_STRING = "indicator_string"; // error / help / hint + String KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING = "error_is_temporary"; + String KEY_BIOMETRIC_INDICATOR_HELP_SHOWING = "hint_is_temporary"; + String KEY_BIOMETRIC_DIALOG_SIZE = "size"; int SIZE_UNKNOWN = 0; int SIZE_SMALL = 1; @@ -68,7 +53,7 @@ public interface AuthDialog { * Show the dialog. * @param wm */ - void show(WindowManager wm); + void show(WindowManager wm, @Nullable Bundle savedState); /** * Dismiss the dialog without sending a callback. @@ -107,13 +92,7 @@ public interface AuthDialog { * Save the current state. * @param outState */ - void onSaveState(Bundle outState); - - /** - * Restore a previous state. - * @param savedState - */ - void restoreState(Bundle savedState); + void onSaveState(@NonNull Bundle outState); /** * Get the client's package name diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java index 89d08d795128..b985e1c2a4d4 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java @@ -23,6 +23,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.annotation.IntDef; +import android.annotation.Nullable; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.graphics.Outline; @@ -738,7 +739,10 @@ public abstract class BiometricDialogView extends LinearLayout implements AuthDi } @Override - public void show(WindowManager wm) { + public void show(WindowManager wm, @Nullable Bundle savedState) { + if (savedState != null) { + restoreState(savedState); + } wm.addView(this, getLayoutParams(mWindowToken)); } @@ -832,7 +836,6 @@ public abstract class BiometricDialogView extends LinearLayout implements AuthDi bundle.putInt(KEY_DIALOG_SIZE, mSize); } - @Override public void restoreState(Bundle bundle) { mRestoredState = bundle; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 13d6470a351f..cc250b46c040 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -168,7 +168,7 @@ public class BubbleStackView extends FrameLayout { * Callback to run after the flyout hides. Also called if a new flyout is shown before the * previous one animates out. */ - private Runnable mAfterFlyoutHides; + private Runnable mFlyoutOnHide; /** Layout change listener that moves the stack to the nearest valid position on rotation. */ private OnLayoutChangeListener mOrientationChangedListener; @@ -1366,111 +1366,106 @@ public class BubbleStackView extends FrameLayout { @VisibleForTesting void animateInFlyoutForBubble(Bubble bubble) { final CharSequence updateMessage = bubble.getUpdateMessage(getContext()); - if (!bubble.showFlyoutForBubble()) { // In case flyout was suppressed for this update, reset now. bubble.setSuppressFlyout(false); return; } - if (updateMessage == null || isExpanded() || mIsExpansionAnimating || mIsGestureInProgress - || mBubbleToExpandAfterFlyoutCollapse != null) { + || mBubbleToExpandAfterFlyoutCollapse != null + || bubble.getIconView() == null) { // Skip the message if none exists, we're expanded or animating expansion, or we're - // about to expand a bubble from the previous tapped flyout. + // about to expand a bubble from the previous tapped flyout, or if bubble view is null. return; } - - if (bubble.getIconView() != null) { - // Temporarily suppress the dot while the flyout is visible. - bubble.getIconView().setSuppressDot( - true /* suppressDot */, false /* animate */); - - mFlyout.removeCallbacks(mAnimateInFlyout); - mFlyoutDragDeltaX = 0f; - - if (mAfterFlyoutHides != null) { - mAfterFlyoutHides.run(); + mFlyoutDragDeltaX = 0f; + clearFlyoutOnHide(); + mFlyoutOnHide = () -> { + resetDot(bubble); + if (mBubbleToExpandAfterFlyoutCollapse == null) { + return; } - - mAfterFlyoutHides = () -> { - final boolean suppressDot = !bubble.showBubbleDot(); - // If we're going to suppress the dot, make it visible first so it'll - // visibly animate away. - if (suppressDot) { - bubble.getIconView().setSuppressDot( - false /* suppressDot */, false /* animate */); - } - // Reset dot suppression. If we're not suppressing due to DND, then - // stop suppressing it with no animation (since the flyout has - // transformed into the dot). If we are suppressing due to DND, animate - // it away. - bubble.getIconView().setSuppressDot( - suppressDot /* suppressDot */, - suppressDot /* animate */); - - if (mBubbleToExpandAfterFlyoutCollapse != null) { - mBubbleData.setSelectedBubble(mBubbleToExpandAfterFlyoutCollapse); - mBubbleData.setExpanded(true); - mBubbleToExpandAfterFlyoutCollapse = null; - } - }; - - mFlyout.setVisibility(INVISIBLE); - - // Post in case layout isn't complete and getWidth returns 0. - post(() -> { - // An auto-expanding bubble could have been posted during the time it takes to - // layout. - if (isExpanded()) { - return; - } - - final Runnable afterShow = () -> { - mAnimateInFlyout = () -> { - mFlyout.setVisibility(VISIBLE); - bubble.getIconView().setSuppressDot( - true /* suppressDot */, false /* animate */); - mFlyoutDragDeltaX = - mStackAnimationController.isStackOnLeftSide() - ? -mFlyout.getWidth() - : mFlyout.getWidth(); - animateFlyoutCollapsed(false /* collapsed */, 0 /* velX */); - mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER); - }; - - mFlyout.postDelayed(mAnimateInFlyout, 200); + mBubbleData.setSelectedBubble(mBubbleToExpandAfterFlyoutCollapse); + mBubbleData.setExpanded(true); + mBubbleToExpandAfterFlyoutCollapse = null; + }; + mFlyout.setVisibility(INVISIBLE); + + // Temporarily suppress the dot while the flyout is visible. + bubble.getIconView().setSuppressDot( + true /* suppressDot */, false /* animate */); + + // Start flyout expansion. Post in case layout isn't complete and getWidth returns 0. + post(() -> { + // An auto-expanding bubble could have been posted during the time it takes to + // layout. + if (isExpanded()) { + return; + } + final Runnable expandFlyoutAfterDelay = () -> { + mAnimateInFlyout = () -> { + mFlyout.setVisibility(VISIBLE); + mFlyoutDragDeltaX = + mStackAnimationController.isStackOnLeftSide() + ? -mFlyout.getWidth() + : mFlyout.getWidth(); + animateFlyoutCollapsed(false /* collapsed */, 0 /* velX */); + mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER); }; - - mFlyout.setupFlyoutStartingAsDot( - updateMessage, mStackAnimationController.getStackPosition(), getWidth(), - mStackAnimationController.isStackOnLeftSide(), - bubble.getIconView().getBadgeColor(), - afterShow, - mAfterFlyoutHides, - bubble.getIconView().getDotCenter()); - mFlyout.bringToFront(); - }); - } - + mFlyout.postDelayed(mAnimateInFlyout, 200); + }; + mFlyout.setupFlyoutStartingAsDot( + updateMessage, mStackAnimationController.getStackPosition(), getWidth(), + mStackAnimationController.isStackOnLeftSide(), + bubble.getIconView().getBadgeColor() /* dotColor */, + expandFlyoutAfterDelay /* onLayoutComplete */, + mFlyoutOnHide, + bubble.getIconView().getDotCenter()); + mFlyout.bringToFront(); + }); mFlyout.removeCallbacks(mHideFlyout); mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER); logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__FLYOUT); } - /** Hide the flyout immediately and cancel any pending hide runnables. */ - private void hideFlyoutImmediate() { - if (mAfterFlyoutHides != null) { - mAfterFlyoutHides.run(); + private void resetDot(Bubble bubble) { + final boolean suppressDot = !bubble.showBubbleDot(); + // If we're going to suppress the dot, make it visible first so it'll + // visibly animate away. + + if (suppressDot) { + bubble.getIconView().setSuppressDot( + false /* suppressDot */, false /* animate */); } + // Reset dot suppression. If we're not suppressing due to DND, then + // stop suppressing it with no animation (since the flyout has + // transformed into the dot). If we are suppressing due to DND, animate + // it away. + bubble.getIconView().setSuppressDot( + suppressDot /* suppressDot */, + suppressDot /* animate */); + } + /** Hide the flyout immediately and cancel any pending hide runnables. */ + private void hideFlyoutImmediate() { + clearFlyoutOnHide(); mFlyout.removeCallbacks(mAnimateInFlyout); mFlyout.removeCallbacks(mHideFlyout); mFlyout.hideFlyout(); } + private void clearFlyoutOnHide() { + mFlyout.removeCallbacks(mAnimateInFlyout); + if (mFlyoutOnHide == null) { + return; + } + mFlyoutOnHide.run(); + mFlyoutOnHide = null; + } + @Override public void getBoundsOnScreen(Rect outRect) { if (!mIsExpanded) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java index 603c4169c169..4512aa822e3b 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java @@ -61,7 +61,7 @@ public class BubbleView extends FrameLayout { // mBubbleIconFactory cannot be static because it depends on Context. private BubbleIconFactory mBubbleIconFactory; - private boolean mSuppressDot = false; + private boolean mSuppressDot; private Bubble mBubble; @@ -140,6 +140,7 @@ public class BubbleView extends FrameLayout { public void setAppIcon(Drawable appIcon) { mUserBadgedAppIcon = appIcon; } + /** * @return the {@link ExpandableNotificationRow} view to display notification content when the * bubble is expanded. @@ -154,7 +155,6 @@ public class BubbleView extends FrameLayout { updateDotVisibility(animate, null /* after */); } - /** * Sets whether or not to hide the dot even if we'd otherwise show it. This is used while the * flyout is visible or animating, to hide the dot until the flyout visually transforms into it. @@ -166,7 +166,7 @@ public class BubbleView extends FrameLayout { /** Sets the position of the 'new' dot, animating it out and back in if requested. */ void setDotPosition(boolean onLeft, boolean animate) { - if (animate && onLeft != mBadgedImageView.getDotOnLeft() && !mSuppressDot) { + if (animate && onLeft != mBadgedImageView.getDotOnLeft() && shouldShowDot()) { animateDot(false /* showDot */, () -> { mBadgedImageView.setDotOnLeft(onLeft); animateDot(true /* showDot */, null); @@ -190,12 +190,12 @@ public class BubbleView extends FrameLayout { * after animation if requested. */ private void updateDotVisibility(boolean animate, Runnable after) { - boolean showDot = mBubble.showBubbleDot() && !mSuppressDot; - + final boolean showDot = shouldShowDot(); if (animate) { animateDot(showDot, after); } else { mBadgedImageView.setShowDot(showDot); + mBadgedImageView.setDotScale(showDot ? 1f : 0f); } } @@ -203,27 +203,25 @@ public class BubbleView extends FrameLayout { * Animates the badge to show or hide. */ private void animateDot(boolean showDot, Runnable after) { - if (mBadgedImageView.isShowingDot() != showDot) { - if (showDot) { - mBadgedImageView.setShowDot(true); - } - mBadgedImageView.clearAnimation(); - mBadgedImageView.animate().setDuration(200) - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .setUpdateListener((valueAnimator) -> { - float fraction = valueAnimator.getAnimatedFraction(); - fraction = showDot ? fraction : 1f - fraction; - mBadgedImageView.setDotScale(fraction); - }).withEndAction(() -> { - if (!showDot) { - mBadgedImageView.setShowDot(false); - } - - if (after != null) { - after.run(); - } - }).start(); + if (mBadgedImageView.isShowingDot() == showDot) { + return; } + // Do NOT wait until after animation ends to setShowDot + // to avoid overriding more recent showDot states. + mBadgedImageView.setShowDot(showDot); + mBadgedImageView.clearAnimation(); + mBadgedImageView.animate().setDuration(200) + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) + .setUpdateListener((valueAnimator) -> { + float fraction = valueAnimator.getAnimatedFraction(); + fraction = showDot ? fraction : 1f - fraction; + mBadgedImageView.setDotScale(fraction); + }).withEndAction(() -> { + mBadgedImageView.setDotScale(showDot ? 1f : 0f); + if (after != null) { + after.run(); + } + }).start(); } void updateViews() { @@ -273,7 +271,11 @@ public class BubbleView extends FrameLayout { iconPath.transform(matrix); mBadgedImageView.drawDot(iconPath); - animateDot(mBubble.showBubbleDot() /* showDot */, null /* after */); + animateDot(shouldShowDot(), null /* after */); + } + + boolean shouldShowDot() { + return mBubble.showBubbleDot() && !mSuppressDot; } int getBadgeColor() { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index e69688079e57..d2a9c750bbc6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -99,6 +99,8 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import javax.inject.Inject; + /** * Mediates requests related to the keyguard. This includes queries about the * state of the keyguard, power management events that effect whether the keyguard @@ -216,6 +218,7 @@ public class KeyguardViewMediator extends SystemUI { private boolean mBootSendUserPresent; private boolean mShuttingDown; private boolean mDozing; + private final FalsingManager mFalsingManager; /** High level access to the power manager for WakeLocks */ private PowerManager mPM; @@ -678,6 +681,13 @@ public class KeyguardViewMediator extends SystemUI { } }; + @Inject + public KeyguardViewMediator(FalsingManager falsingManager) { + super(); + + mFalsingManager = falsingManager; + } + public void userActivity() { mPM.userActivity(SystemClock.uptimeMillis(), false); } @@ -1603,7 +1613,7 @@ public class KeyguardViewMediator extends SystemUI { Trace.beginSection("KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM"); StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj; handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration); - Dependency.get(FalsingManager.class).onSucccessfulUnlock(); + mFalsingManager.onSucccessfulUnlock(); Trace.endSection(); break; case KEYGUARD_DONE_PENDING_TIMEOUT: @@ -2075,11 +2085,10 @@ public class KeyguardViewMediator extends SystemUI { public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar, ViewGroup container, NotificationPanelView panelView, BiometricUnlockController biometricUnlockController, ViewGroup lockIconContainer, - View notificationContainer, KeyguardBypassController bypassController, - FalsingManager falsingManager) { + View notificationContainer, KeyguardBypassController bypassController) { mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container, panelView, biometricUnlockController, mDismissCallbackRegistry, lockIconContainer, - notificationContainer, bypassController, falsingManager); + notificationContainer, bypassController, mFalsingManager); return mStatusBarKeyguardViewManager; } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 9c65994425ed..fa6047755619 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -551,9 +551,8 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call return true; } - mActivityTaskManager.resizeStack(stackInfo.stackId, toBounds, - false /* allowResizeInDockedMode */, true /* preserveWindows */, - true /* animate */, duration); + mActivityTaskManager.animateResizePinnedStack(stackInfo.stackId, toBounds, + duration); mBounds.set(toBounds); } catch (RemoteException e) { Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e); diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 5f2614ef4479..918af4f0cd4c 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -441,8 +441,8 @@ public class PipManager implements BasePipManager { } try { int animationDurationMs = -1; - mActivityTaskManager.resizeStack(mPinnedStackId, mCurrentPipBounds, - true, true, true, animationDurationMs); + mActivityTaskManager.animateResizePinnedStack(mPinnedStackId, mCurrentPipBounds, + animationDurationMs); } catch (RemoteException e) { Log.e(TAG, "resizeStack failed", e); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java index b135f7b27c3f..effea6a877b8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java @@ -159,8 +159,11 @@ public class TileLifecycleManager extends BroadcastReceiver implements mBindTryCount++; try { mIsBound = mContext.bindServiceAsUser(mIntent, this, - Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE - | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, mUser); + Context.BIND_AUTO_CREATE + | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE + | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS + | Context.BIND_WAIVE_PRIORITY, + mUser); } catch (SecurityException e) { Log.e(TAG, "Failed to bind to service", e); mIsBound = false; 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 2964889f1399..6f5fe8b629fb 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 @@ -31,6 +31,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BA import android.annotation.NonNull; import android.app.Notification; +import android.app.Notification.MessagingStyle.Message; import android.app.NotificationChannel; import android.app.NotificationManager.Policy; import android.app.Person; @@ -89,7 +90,6 @@ public final class NotificationEntry { public StatusBarNotification notification; private Ranking mRanking; - public NotificationChannel channel; public long lastAudiblyAlertedMs; public boolean noisy; public boolean ambient; @@ -243,7 +243,6 @@ public final class NotificationEntry { public void setRanking(@NonNull Ranking ranking) { mRanking = ranking; - channel = ranking.getChannel(); lastAudiblyAlertedMs = ranking.getLastAudiblyAlertedMillis(); importance = ranking.getImportance(); ambient = ranking.isAmbient(); @@ -259,6 +258,10 @@ public final class NotificationEntry { canBubble = ranking.canBubble(); } + public NotificationChannel getChannel() { + return mRanking.getChannel(); + } + public void setInterruption() { interruption = true; } @@ -545,21 +548,18 @@ public final class NotificationEntry { if (!ArrayUtils.isEmpty(replyTexts)) { return true; } - Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES); - if (messages != null && messages.length > 0) { - Parcelable message = messages[messages.length - 1]; - if (message instanceof Bundle) { - Notification.MessagingStyle.Message lastMessage = - Notification.MessagingStyle.Message.getMessageFromBundle( - (Bundle) message); - if (lastMessage != null) { - Person senderPerson = lastMessage.getSenderPerson(); - if (senderPerson == null) { - return true; - } - Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON); - return Objects.equals(user, senderPerson); + List<Message> messages = Message.getMessagesFromBundleArray( + extras.getParcelableArray(Notification.EXTRA_MESSAGES)); + if (messages != null && !messages.isEmpty()) { + Message lastMessage = messages.get(messages.size() -1); + + if (lastMessage != null) { + Person senderPerson = lastMessage.getSenderPerson(); + if (senderPerson == null) { + return true; } + Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON); + return Objects.equals(user, senderPerson); } } return false; 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 12d537d3c646..0f6ce2153488 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 @@ -520,7 +520,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public boolean getIsNonblockable() { boolean isNonblockable = Dependency.get(NotificationBlockingHelperManager.class) .isNonblockable(mStatusBarNotification.getPackageName(), - mEntry.channel.getId()); + mEntry.getChannel().getId()); // If the SystemNotifAsyncTask hasn't finished running or retrieved a value, we'll try once // again, but in-place on the main thread this time. This should rarely ever get called. @@ -532,13 +532,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mEntry.mIsSystemNotification = isSystemNotification(mContext, mStatusBarNotification); } - isNonblockable |= mEntry.channel.isImportanceLockedByOEM(); - isNonblockable |= mEntry.channel.isImportanceLockedByCriticalDeviceFunction(); + isNonblockable |= mEntry.getChannel().isImportanceLockedByOEM(); + isNonblockable |= mEntry.getChannel().isImportanceLockedByCriticalDeviceFunction(); if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) { if (mEntry.mIsSystemNotification) { - if (mEntry.channel != null - && !mEntry.channel.isBlockableSystem()) { + if (mEntry.getChannel() != null + && !mEntry.getChannel().isBlockableSystem()) { isNonblockable = true; } } @@ -2389,7 +2389,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public ArraySet<NotificationChannel> getUniqueChannels() { ArraySet<NotificationChannel> channels = new ArraySet<>(); - channels.add(mEntry.channel); + channels.add(mEntry.getChannel()); // If this is a summary, then add in the children notification channels for the // same user and pkg. @@ -2398,7 +2398,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView final int numChildren = childrenRows.size(); for (int i = 0; i < numChildren; i++) { final ExpandableNotificationRow childRow = childrenRows.get(i); - final NotificationChannel childChannel = childRow.getEntry().channel; + final NotificationChannel childChannel = childRow.getEntry().getChannel(); final StatusBarNotification childSbn = childRow.getStatusBarNotification(); if (childSbn.getUser().equals(mStatusBarNotification.getUser()) && childSbn.getPackageName().equals(mStatusBarNotification.getPackageName())) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 8f7671a5dd96..3e8825d735da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -316,7 +316,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx iNotificationManager, mVisualStabilityManager, packageName, - row.getEntry().channel, + row.getEntry().getChannel(), row.getUniqueChannels(), sbn, mCheckSaveListener, 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 fe96ef764875..6b12c6158948 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1263,7 +1263,7 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, getBouncerContainer(), mNotificationPanel, mBiometricUnlockController, mStatusBarWindow.findViewById(R.id.lock_icon_container), mStackScroller, - mKeyguardBypassController, mFalsingManager); + mKeyguardBypassController); mKeyguardIndicationController .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index 94ca9e9c9b51..819a7f6fde1a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -29,6 +29,7 @@ import android.util.Log; import androidx.test.InstrumentationRegistry; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.util.Assert; @@ -78,6 +79,7 @@ public abstract class SysuiTestCase { // A lot of tests get the FalsingManager, often via several layers of indirection. // None of them actually need it. mDependency.injectTestDependency(FalsingManager.class, new FalsingManagerFake()); + mDependency.injectMockDependency(KeyguardUpdateMonitor.class); } @After diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java index 128e819ccedd..b907cdb54bbf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java @@ -63,7 +63,7 @@ public class AuthBiometricFaceViewTest extends SysuiTestCase { mFaceView.mNegativeButton = mNegativeButton; mFaceView.mPositiveButton = mPositiveButton; mFaceView.mTryAgainButton = mTryAgainButton; - mFaceView.mErrorView = mErrorView; + mFaceView.mIndicatorView = mErrorView; } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java index ffcb293ba398..fc1870738375 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java @@ -17,12 +17,15 @@ package com.android.systemui.biometrics; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.content.Context; +import android.hardware.biometrics.BiometricPrompt; +import android.os.Bundle; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; @@ -55,10 +58,10 @@ public class AuthBiometricViewTest extends SysuiTestCase { @Mock private TextView mTitleView; @Mock private TextView mSubtitleView; @Mock private TextView mDescriptionView; - @Mock private TextView mErrorView; + @Mock private TextView mIndicatorView; @Mock private ImageView mIconView; - TestableBiometricView mBiometricView; + private TestableBiometricView mBiometricView; @Before public void setup() { @@ -87,8 +90,8 @@ public class AuthBiometricViewTest extends SysuiTestCase { verify(mCallback, never()).onAction(anyInt()); verify(mBiometricView.mNegativeButton).setText(eq(R.string.cancel)); verify(mBiometricView.mPositiveButton).setEnabled(eq(true)); - verify(mErrorView).setText(eq(R.string.biometric_dialog_tap_confirm)); - verify(mErrorView).setVisibility(eq(View.VISIBLE)); + verify(mIndicatorView).setText(eq(R.string.biometric_dialog_tap_confirm)); + verify(mIndicatorView).setVisibility(eq(View.VISIBLE)); } @Test @@ -193,11 +196,88 @@ public class AuthBiometricViewTest extends SysuiTestCase { verify(mCallback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED)); } + @Test + public void testRestoresState() { + final boolean requireConfirmation = true; // set/init from AuthController + + Button tryAgainButton = new Button(mContext); + TextView indicatorView = new TextView(mContext); + initDialog(mContext, mCallback, new MockInjector() { + @Override + public Button getTryAgainButton() { + return tryAgainButton; + } + @Override + public TextView getIndicatorView() { + return indicatorView; + } + }); + + final String failureMessage = "testFailureMessage"; + mBiometricView.setRequireConfirmation(requireConfirmation); + mBiometricView.onAuthenticationFailed(failureMessage); + waitForIdleSync(); + + Bundle state = new Bundle(); + mBiometricView.onSaveState(state); + + assertEquals(View.VISIBLE, tryAgainButton.getVisibility()); + assertEquals(View.VISIBLE, state.getInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY)); + + assertEquals(AuthBiometricView.STATE_ERROR, mBiometricView.mState); + assertEquals(AuthBiometricView.STATE_ERROR, state.getInt(AuthDialog.KEY_BIOMETRIC_STATE)); + + assertEquals(View.VISIBLE, mBiometricView.mIndicatorView.getVisibility()); + assertTrue(state.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING)); + + assertEquals(failureMessage, mBiometricView.mIndicatorView.getText()); + assertEquals(failureMessage, state.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING)); + + // TODO: Test dialog size. Should move requireConfirmation to buildBiometricPromptBundle + + // Create new dialog and restore the previous state into it + Button tryAgainButton2 = new Button(mContext); + TextView indicatorView2 = new TextView(mContext); + initDialog(mContext, mCallback, state, new MockInjector() { + @Override + public Button getTryAgainButton() { + return tryAgainButton2; + } + @Override + public TextView getIndicatorView() { + return indicatorView2; + } + }); + mBiometricView.setRequireConfirmation(requireConfirmation); + waitForIdleSync(); + + // Test restored state + assertEquals(View.VISIBLE, tryAgainButton.getVisibility()); + assertEquals(AuthBiometricView.STATE_ERROR, mBiometricView.mState); + assertEquals(View.VISIBLE, mBiometricView.mIndicatorView.getVisibility()); + assertEquals(failureMessage, mBiometricView.mIndicatorView.getText()); + } + + private Bundle buildBiometricPromptBundle() { + Bundle bundle = new Bundle(); + bundle.putCharSequence(BiometricPrompt.KEY_TITLE, "Title"); + bundle.putCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT, "Negative"); + return bundle; + } + private void initDialog(Context context, AuthBiometricView.Callback callback, - MockInjector injector) { + Bundle savedState, MockInjector injector) { mBiometricView = new TestableBiometricView(context, null, injector); + mBiometricView.setBiometricPromptBundle(buildBiometricPromptBundle()); mBiometricView.setCallback(callback); - mBiometricView.initializeViews(); + mBiometricView.restoreState(savedState); + mBiometricView.onFinishInflateInternal(); + mBiometricView.onAttachedToWindowInternal(); + } + + private void initDialog(Context context, AuthBiometricView.Callback callback, + MockInjector injector) { + initDialog(context, callback, null /* savedState */, injector); } private class MockInjector extends AuthBiometricView.Injector { @@ -232,8 +312,8 @@ public class AuthBiometricViewTest extends SysuiTestCase { } @Override - public TextView getErrorView() { - return mErrorView; + public TextView getIndicatorView() { + return mIndicatorView; } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index a5e468e0545d..eb7be4fa6332 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -147,7 +147,7 @@ public class AuthControllerTest extends SysuiTestCase { public void testShowInvoked_whenSystemRequested() throws Exception { showDialog(BiometricPrompt.TYPE_FACE); - verify(mDialog1).show(any()); + verify(mDialog1).show(any(), any()); } @Test @@ -215,7 +215,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testShowNewDialog_beforeOldDialogDismissed_SkipsAnimations() throws Exception { showDialog(BiometricPrompt.TYPE_FACE); - verify(mDialog1).show(any()); + verify(mDialog1).show(any(), any()); showDialog(BiometricPrompt.TYPE_FACE); @@ -223,13 +223,13 @@ public class AuthControllerTest extends SysuiTestCase { verify(mDialog1).dismissWithoutCallback(eq(false) /* animate */); // Second dialog should be shown without animation - verify(mDialog2).show(any()); + verify(mDialog2).show(any(), any()); } @Test public void testConfigurationPersists_whenOnConfigurationChanged() throws Exception { showDialog(BiometricPrompt.TYPE_FACE); - verify(mDialog1).show(any()); + verify(mDialog1).show(any(), any()); mBiometricDialogImpl.onConfigurationChanged(new Configuration()); @@ -241,10 +241,7 @@ public class AuthControllerTest extends SysuiTestCase { // Saved state is restored into new dialog ArgumentCaptor<Bundle> captor2 = ArgumentCaptor.forClass(Bundle.class); - verify(mDialog2).restoreState(captor2.capture()); - - // Dialog for new configuration skips intro - verify(mDialog2).show(any()); + verify(mDialog2).show(any(), captor2.capture()); // TODO: This should check all values we want to save/restore assertEquals(captor.getValue(), captor2.getValue()); 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 ba434d4fd0bd..448c80ef3c57 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -71,8 +71,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.DozeParameters; -import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -165,7 +165,8 @@ public class BubbleControllerTest extends SysuiTestCase { // Return non-null notification data from the NEM when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData); when(mNotificationData.get(mRow.getEntry().key)).thenReturn(mRow.getEntry()); - when(mNotificationData.getChannel(mRow.getEntry().key)).thenReturn(mRow.getEntry().channel); + when(mNotificationData.getChannel(mRow.getEntry().key)).thenReturn( + mRow.getEntry().getChannel()); mZenModeConfig.suppressedVisualEffects = 0; when(mZenModeController.getConfig()).thenReturn(mZenModeConfig); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java index 264a5400f1a5..7cd58193a3e7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java @@ -306,12 +306,21 @@ public class NotificationTestHelper { userHandle, null /* overrideGroupKey */, System.currentTimeMillis()); - NotificationEntry entry = NotificationEntry.buildForTest(sbn); + final NotificationChannel channel = + new NotificationChannel( + notification.getChannelId(), + notification.getChannelId(), + importance); + channel.setBlockableSystem(true); + + NotificationEntry entry = new NotificationEntry( + sbn, + new RankingBuilder() + .setKey(sbn.getKey()) + .setChannel(channel) + .build()); entry.setRow(row); entry.createIcons(mContext, sbn); - entry.channel = new NotificationChannel( - notification.getChannelId(), notification.getChannelId(), importance); - entry.channel.setBlockableSystem(true); row.setEntry(entry); row.getNotificationInflater().addInflationFlags(extraInflationFlags); NotificationContentInflaterTest.runThenWaitForInflation( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java new file mode 100644 index 000000000000..bbdc4b7fc360 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java @@ -0,0 +1,105 @@ +/* + * 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.statusbar; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.service.notification.NotificationListenerService.Ranking; +import android.service.notification.SnoozeCriterion; + +import java.util.ArrayList; + +/** + * Standard builder class for Ranking objects. For use in tests that need to craft the underlying + * Ranking object of a NotificationEntry. + */ +public class RankingBuilder { + private String mKey = "test_key"; + private int mRank = 0; + private boolean mMatchesInterruptionFilter = false; + private int mVisibilityOverride = 0; + private int mSuppressedVisualEffects = 0; + private int mImportance = 0; + private CharSequence mExplanation = "test_explanation"; + private String mOverrideGroupKey = null; + private NotificationChannel mChannel = null; + private ArrayList<String> mOverridePeople = null; + private ArrayList<SnoozeCriterion> mSnoozeCriteria = null; + private boolean mShowBadge = false; + private int mUserSentiment = 0; + private boolean mHidden = false; + private long mLastAudiblyAlertedMs = 0; + private boolean mNoisy = false; + private ArrayList<Notification.Action> mSmartActions = null; + private ArrayList<CharSequence> mSmartReplies = null; + private boolean mCanBubble = false; + + public RankingBuilder setKey(String key) { + mKey = key; + return this; + } + + public RankingBuilder setImportance(int importance) { + mImportance = importance; + return this; + } + + public RankingBuilder setUserSentiment(int userSentiment) { + mUserSentiment = userSentiment; + return this; + } + + public RankingBuilder setChannel(NotificationChannel channel) { + mChannel = channel; + return this; + } + + public RankingBuilder setSmartActions(ArrayList<Notification.Action> smartActions) { + mSmartActions = smartActions; + return this; + } + + public RankingBuilder setSmartReplies(ArrayList<CharSequence> smartReplies) { + mSmartReplies = smartReplies; + return this; + } + + public Ranking build() { + final Ranking ranking = new Ranking(); + ranking.populate( + mKey, + mRank, + mMatchesInterruptionFilter, + mVisibilityOverride, + mSuppressedVisualEffects, + mImportance, + mExplanation, + mOverrideGroupKey, + mChannel, + mOverridePeople, + mSnoozeCriteria, + mShowBadge, + mUserSentiment, + mHidden, + mLastAudiblyAlertedMs, + mNoisy, + mSmartActions, + mSmartReplies, + mCanBubble); + return ranking; + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java index ed719d99a980..45173a2ef797 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java @@ -145,7 +145,7 @@ public class NotificationDataTest extends SysuiTestCase { override.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL); mNotificationData.rankingOverrides.put(mRow.getEntry().key, override); mNotificationData.add(mRow.getEntry()); - assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().channel); + assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().getChannel()); } @Test @@ -343,7 +343,7 @@ public class NotificationDataTest extends SysuiTestCase { new NotificationEntry(mMockStatusBarNotification, ranking); assertEquals(systemGeneratedSmartActions, entry.systemGeneratedSmartActions); - assertEquals(NOTIFICATION_CHANNEL, entry.channel); + assertEquals(NOTIFICATION_CHANNEL, entry.getChannel()); assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.userSentiment); assertEquals(snoozeCriterions, entry.snoozeCriteria); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index d526d104630e..a14557bd9684 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -51,6 +51,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationTestHelper; +import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.notification.AboveShelfChangedListener; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer; @@ -327,8 +328,11 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { // Give each child a unique channel id/name. int i = 0; for (ExpandableNotificationRow childRow : childRows) { - childRow.getEntry().channel = - new NotificationChannel("id" + i, "dinnertime" + i, IMPORTANCE_DEFAULT); + childRow.getEntry().setRanking(new RankingBuilder() + .setChannel( + new NotificationChannel( + "id" + i, "dinnertime" + i, IMPORTANCE_DEFAULT)) + .build()); i++; } @@ -364,7 +368,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { public void testGetIsNonblockable_oemLocked() throws Exception { ExpandableNotificationRow row = mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification()); - row.getEntry().channel.setImportanceLockedByOEM(true); + row.getEntry().getChannel().setImportanceLockedByOEM(true); assertTrue(row.getIsNonblockable()); } @@ -373,7 +377,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { public void testGetIsNonblockable_criticalDeviceFunction() throws Exception { ExpandableNotificationRow row = mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification()); - row.getEntry().channel.setImportanceLockedByCriticalDeviceFunction(true); + row.getEntry().getChannel().setImportanceLockedByCriticalDeviceFunction(true); assertTrue(row.getIsNonblockable()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java index 3c91b3f1bdd3..a26cdbd30b47 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java @@ -41,8 +41,10 @@ import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.NotificationTestHelper; +import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.util.Assert; @@ -73,6 +75,7 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase { public void setUp() { Assert.sMainLooper = TestableLooper.get(this).getLooper(); MockitoAnnotations.initMocks(this); + mDependency.injectMockDependency(BubbleController.class); when(mGutsManager.openGuts( any(View.class), anyInt(), @@ -82,6 +85,7 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase { when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem); mDependency.injectTestDependency(NotificationGutsManager.class, mGutsManager); mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager); + mDependency.injectMockDependency(BubbleController.class); mHelper = new NotificationTestHelper(mContext); @@ -138,8 +142,11 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase { ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(10); int i = 0; for (ExpandableNotificationRow childRow : groupRow.getNotificationChildren()) { - childRow.getEntry().channel = - new NotificationChannel(Integer.toString(i++), "", IMPORTANCE_DEFAULT); + childRow.getEntry().setRanking(new RankingBuilder() + .setChannel( + new NotificationChannel( + Integer.toString(i++), "", IMPORTANCE_DEFAULT)) + .build()); } groupRow.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 795948470295..09c4179185fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -62,6 +62,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationTestHelper; +import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -498,7 +499,10 @@ public class NotificationGutsManagerTest extends SysuiTestCase { try { ExpandableNotificationRow row = mHelper.createRow(nb.build()); - row.getEntry().channel = mTestNotificationChannel; + row.getEntry().setRanking( + new RankingBuilder() + .setChannel(mTestNotificationChannel) + .build()); return row; } catch (Exception e) { fail(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java index 98e1692c2368..096acf9d9ce4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java @@ -40,6 +40,7 @@ import android.view.ViewGroup; import androidx.test.filters.SmallTest; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.utils.leaks.LeakCheckedTest; @@ -60,9 +61,11 @@ public class NotificationMenuRowTest extends LeakCheckedTest { public void setup() { injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); mRow = mock(ExpandableNotificationRow.class); - NotificationEntry entry = NotificationEntry.buildForTest( - mock(StatusBarNotification.class)); - entry.channel = mock(NotificationChannel.class); + NotificationEntry entry = new NotificationEntry( + mock(StatusBarNotification.class), + new RankingBuilder() + .setChannel(mock(NotificationChannel.class)) + .build()); when(mRow.getEntry()).thenReturn(entry); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9b1eb3a62185..fbd77577b4bf 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6324,13 +6324,6 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void resizeStack(int stackId, Rect destBounds, boolean allowResizeInDockedMode, - boolean preserveWindows, boolean animate, int animationDuration) { - mActivityTaskManager.resizeStack(stackId, destBounds, allowResizeInDockedMode, - preserveWindows, animate, animationDuration); - } - - @Override public ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags, int userId) { return mActivityTaskManager.getRecentTasks(maxNum, flags, userId); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 8b8c40e1346b..d46c62662faf 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -2481,8 +2481,6 @@ final class ActivityManagerShellCommand extends ShellCommand { switch (op) { case "move-task": return runStackMoveTask(pw); - case "resize": - return runStackResize(pw); case "resize-animated": return runStackResizeAnimated(pw); case "resize-docked-stack": @@ -2561,17 +2559,6 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } - int runStackResize(PrintWriter pw) throws RemoteException { - String stackIdStr = getNextArgRequired(); - int stackId = Integer.parseInt(stackIdStr); - final Rect bounds = getBounds(); - if (bounds == null) { - getErrPrintWriter().println("Error: invalid input bounds"); - return -1; - } - return resizeStack(stackId, bounds, 0); - } - int runStackResizeAnimated(PrintWriter pw) throws RemoteException { String stackIdStr = getNextArgRequired(); int stackId = Integer.parseInt(stackIdStr); @@ -2585,16 +2572,7 @@ final class ActivityManagerShellCommand extends ShellCommand { return -1; } } - return resizeStackUnchecked(stackId, bounds, 0, true); - } - - int resizeStackUnchecked(int stackId, Rect bounds, int delayMs, boolean animate) - throws RemoteException { - try { - mTaskInterface.resizeStack(stackId, bounds, false, false, animate, -1); - Thread.sleep(delayMs); - } catch (InterruptedException e) { - } + mTaskInterface.animateResizePinnedStack(stackId, bounds, -1); return 0; } @@ -2609,14 +2587,6 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } - int resizeStack(int stackId, Rect bounds, int delayMs) throws RemoteException { - if (bounds == null) { - getErrPrintWriter().println("Error: invalid input bounds"); - return -1; - } - return resizeStackUnchecked(stackId, bounds, delayMs, false); - } - int runStackPositionTask(PrintWriter pw) throws RemoteException { String taskIdStr = getNextArgRequired(); int taskId = Integer.parseInt(taskIdStr); @@ -3195,8 +3165,6 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" move-task <TASK_ID> <STACK_ID> [true|false]"); pw.println(" Move <TASK_ID> from its current stack to the top (true) or"); pw.println(" bottom (false) of <STACK_ID>."); - pw.println(" resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>"); - pw.println(" Change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>."); pw.println(" resize-animated <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>"); pw.println(" Same as resize, but allow animation."); pw.println(" resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]"); diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java index 8de259516890..09f52860e069 100644 --- a/services/core/java/com/android/server/camera/CameraServiceProxy.java +++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java @@ -36,6 +36,7 @@ import android.os.UserManager; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; +import android.util.StatsLog; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -44,6 +45,9 @@ import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.wm.WindowManagerInternal; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -102,6 +106,9 @@ public class CameraServiceProxy extends SystemService private final boolean mNotifyNfc; + private ScheduledThreadPoolExecutor mLogWriterService = new ScheduledThreadPoolExecutor( + /*corePoolSize*/ 1); + /** * Structure to track camera usage */ @@ -204,6 +211,9 @@ public class CameraServiceProxy extends SystemService mNotifyNfc = SystemProperties.getInt(NFC_NOTIFICATION_PROP, 0) > 0; if (DEBUG) Slog.v(TAG, "Notify NFC behavior is " + (mNotifyNfc ? "active" : "disabled")); + // Don't keep any extra logging threads if not needed + mLogWriterService.setKeepAliveTime(1, TimeUnit.SECONDS); + mLogWriterService.allowCoreThreadTimeOut(true); } @Override @@ -279,6 +289,51 @@ public class CameraServiceProxy extends SystemService } } + private class EventWriterTask implements Runnable { + private ArrayList<CameraUsageEvent> mEventList; + private static final long WRITER_SLEEP_MS = 100; + + public EventWriterTask(ArrayList<CameraUsageEvent> eventList) { + mEventList = eventList; + } + + @Override + public void run() { + if (mEventList != null) { + for (CameraUsageEvent event : mEventList) { + logCameraUsageEvent(event); + try { + Thread.sleep(WRITER_SLEEP_MS); + } catch (InterruptedException e) {} + } + mEventList.clear(); + } + } + + /** + * Write camera usage events to stats log. + * Package-private + */ + private void logCameraUsageEvent(CameraUsageEvent e) { + int facing = StatsLog.CAMERA_ACTION_EVENT__FACING__UNKNOWN; + switch(e.mCameraFacing) { + case ICameraServiceProxy.CAMERA_FACING_BACK: + facing = StatsLog.CAMERA_ACTION_EVENT__FACING__BACK; + break; + case ICameraServiceProxy.CAMERA_FACING_FRONT: + facing = StatsLog.CAMERA_ACTION_EVENT__FACING__FRONT; + break; + case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: + facing = StatsLog.CAMERA_ACTION_EVENT__FACING__EXTERNAL; + break; + default: + Slog.w(TAG, "Unknown camera facing: " + e.mCameraFacing); + } + StatsLog.write(StatsLog.CAMERA_ACTION_EVENT, e.getDuration(), e.mAPILevel, + e.mClientName, facing); + } + } + /** * Dump camera usage events to log. * Package-private @@ -315,6 +370,10 @@ public class CameraServiceProxy extends SystemService .setPackageName(e.mClientName); mLogger.write(l); } + + mLogWriterService.execute(new EventWriterTask( + new ArrayList<CameraUsageEvent>(mCameraUsageHistory))); + mCameraUsageHistory.clear(); } final long ident = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index db8d0988e75c..f71b3627135d 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -457,7 +457,7 @@ public class NotificationManagerService extends SystemService { private static final int MY_UID = Process.myUid(); private static final int MY_PID = Process.myPid(); private static final IBinder WHITELIST_TOKEN = new Binder(); - private RankingHandler mRankingHandler; + protected RankingHandler mRankingHandler; private long mLastOverRateLogTime; private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; @@ -1550,10 +1550,12 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting void clearNotifications() { - mEnqueuedNotifications.clear(); - mNotificationList.clear(); - mNotificationsByKey.clear(); - mSummaryByGroupKey.clear(); + synchronized (mNotificationList) { + mEnqueuedNotifications.clear(); + mNotificationList.clear(); + mNotificationsByKey.clear(); + mSummaryByGroupKey.clear(); + } } @VisibleForTesting @@ -1605,11 +1607,6 @@ public class NotificationManagerService extends SystemService { void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; } @VisibleForTesting - void setRankingHandler(RankingHandler rankingHandler) { - mRankingHandler = rankingHandler; - } - - @VisibleForTesting void setZenHelper(ZenModeHelper zenHelper) { mZenModeHelper = zenHelper; } @@ -1641,7 +1638,7 @@ public class NotificationManagerService extends SystemService { // TODO: All tests should use this init instead of the one-off setters above. @VisibleForTesting - void init(Looper looper, IPackageManager packageManager, + void init(Looper looper, RankingHandler rankingHandler, IPackageManager packageManager, PackageManager packageManagerClient, LightsManager lightsManager, NotificationListeners notificationListeners, NotificationAssistants notificationAssistants, ConditionProviders conditionProviders, @@ -1675,7 +1672,6 @@ public class NotificationManagerService extends SystemService { mUm = userManager; mHandler = new WorkerHandler(looper); - mRankingThread.start(); String[] extractorNames; try { extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); @@ -1684,7 +1680,7 @@ public class NotificationManagerService extends SystemService { } mUsageStats = usageStats; mMetricsLogger = new MetricsLogger(); - mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper()); + mRankingHandler = rankingHandler; mConditionProviders = conditionProviders; mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders); mZenModeHelper.addCallback(new ZenModeHelper.Callback() { @@ -1829,8 +1825,9 @@ public class NotificationManagerService extends SystemService { }, mUserProfiles); final File systemDir = new File(Environment.getDataDirectory(), "system"); + mRankingThread.start(); - init(Looper.myLooper(), + init(Looper.myLooper(), new RankingHandlerWorker(mRankingThread.getLooper()), AppGlobals.getPackageManager(), getContext().getPackageManager(), getLocalService(LightsManager.class), new NotificationListeners(AppGlobals.getPackageManager()), diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java index c6af7566a8bd..8f05636eed9c 100644 --- a/services/core/java/com/android/server/notification/ZenLog.java +++ b/services/core/java/com/android/server/notification/ZenLog.java @@ -179,6 +179,7 @@ public class ZenLog { case TYPE_SUPPRESSOR_CHANGED: return "suppressor_changed"; case TYPE_LISTENER_HINTS_CHANGED: return "listener_hints_changed"; case TYPE_SET_NOTIFICATION_POLICY: return "set_notification_policy"; + case TYPE_SET_CONSOLIDATED_ZEN_POLICY: return "set_consolidated_policy"; default: return "unknown"; } } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index ee948b28e546..f63aa5256078 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -954,12 +954,11 @@ public class ZenModeHelper { } private void applyCustomPolicy(ZenPolicy policy, ZenRule rule) { - if (rule.zenMode == NotificationManager.INTERRUPTION_FILTER_NONE) { + if (rule.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) { policy.apply(new ZenPolicy.Builder() .disallowAllSounds() .build()); - } else if (rule.zenMode - == NotificationManager.INTERRUPTION_FILTER_ALARMS) { + } else if (rule.zenMode == Global.ZEN_MODE_ALARMS) { policy.apply(new ZenPolicy.Builder() .disallowAllSounds() .allowAlarms(true) diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index f5f6625c8728..b92625fe14af 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -33,6 +33,7 @@ import static android.app.WindowConfiguration.windowingModeToString; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; +import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; import static android.view.Display.INVALID_DISPLAY; @@ -134,6 +135,7 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.SystemClock; +import android.os.Trace; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; import android.util.ArraySet; @@ -635,11 +637,15 @@ class ActivityStack extends ConfigurationContainer { display.onStackWindowingModeChanged(this); } if (hasNewOverrideBounds) { - // Note the resizeStack may enter onConfigurationChanged recursively, so we make a copy - // of the temporary bounds (newBounds is mTmpRect) to avoid it being modified. - mRootActivityContainer.resizeStack(this, new Rect(newBounds), null /* tempTaskBounds */, - null /* tempTaskInsetBounds */, PRESERVE_WINDOWS, - true /* allowResizeInDockedMode */, true /* deferResume */); + if (inSplitScreenPrimaryWindowingMode()) { + mStackSupervisor.resizeDockedStackLocked(new Rect(newBounds), + null /* tempTaskBounds */, null /* tempTaskInsetBounds */, + null /* tempOtherTaskBounds */, null /* tempOtherTaskInsetBounds */, + PRESERVE_WINDOWS, true /* deferResume */); + } else { + resize(new Rect(newBounds), null /* tempTaskBounds */, + null /* tempTaskInsetBounds */, PRESERVE_WINDOWS, true /* deferResume */); + } } if (prevIsAlwaysOnTop != isAlwaysOnTop()) { // Since always on top is only on when the stack is freeform or pinned, the state @@ -818,7 +824,8 @@ class ActivityStack extends ConfigurationContainer { } if (!Objects.equals(getRequestedOverrideBounds(), mTmpRect2)) { - resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */); + resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, + false /* preserveWindows */, true /* deferResume */); } } finally { if (showRecents && !alreadyInSplitScreenMode && mDisplayId == DEFAULT_DISPLAY @@ -2208,7 +2215,7 @@ class ActivityStack extends ConfigurationContainer { * Returns true if this stack should be resized to match the bounds specified by * {@link ActivityOptions#setLaunchBounds} when launching an activity into the stack. */ - boolean resizeStackWithLaunchBounds() { + boolean shouldResizeStackWithLaunchBounds() { return inPinnedWindowingMode(); } @@ -4344,31 +4351,42 @@ class ActivityStack extends ConfigurationContainer { } } - // TODO: Figure-out a way to consolidate with resize() method below. - void requestResize(Rect bounds) { - mService.resizeStack(mStackId, bounds, - true /* allowResizeInDockedMode */, false /* preserveWindows */, - false /* animate */, -1 /* animationDuration */); - } - // TODO: Can only be called from special methods in ActivityStackSupervisor. // Need to consolidate those calls points into this resize method so anyone can call directly. - void resize(Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds) { + void resize(Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds, + boolean preserveWindows, boolean deferResume) { if (!updateBoundsAllowed(bounds)) { return; } - // Update override configurations of all tasks in the stack. - final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds; + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "stack.resize_" + mStackId); + mWindowManager.deferSurfaceLayout(); + try { + // Update override configurations of all tasks in the stack. + final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds; + for (int i = mTaskHistory.size() - 1; i >= 0; i--) { + final TaskRecord task = mTaskHistory.get(i); + if (task.isResizeable()) { + if (tempTaskInsetBounds != null && !tempTaskInsetBounds.isEmpty()) { + task.setDisplayedBounds(taskBounds); + task.setBounds(tempTaskInsetBounds); + } else { + task.setDisplayedBounds(null); + task.setBounds(taskBounds); + } + } + } - for (int i = mTaskHistory.size() - 1; i >= 0; i--) { - final TaskRecord task = mTaskHistory.get(i); - if (task.isResizeable()) { - task.updateOverrideConfiguration(taskBounds, tempTaskInsetBounds); + setBounds(bounds); + + if (!deferResume) { + ensureVisibleActivitiesConfigurationLocked( + topRunningActivityLocked(), preserveWindows); } + } finally { + mWindowManager.continueSurfaceLayout(); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } - - setBounds(bounds); } void onPipAnimationEndResize() { @@ -4497,18 +4515,27 @@ class ActivityStack extends ConfigurationContainer { * then skip running tasks that match those types. */ void getRunningTasks(List<TaskRecord> tasksOut, @ActivityType int ignoreActivityType, - @WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed) { + @WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed, + boolean crossUser) { boolean focusedStack = mRootActivityContainer.getTopDisplayFocusedStack() == this; boolean topTask = true; + int userId = UserHandle.getUserId(callingUid); for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = mTaskHistory.get(taskNdx); if (task.getTopActivity() == null) { // Skip if there are no activities in the task continue; } - if (!allowed && !task.isActivityTypeHome() && task.effectiveUid != callingUid) { - // Skip if the caller can't fetch this task - continue; + if (task.effectiveUid != callingUid) { + if (task.userId != userId && !crossUser) { + // Skip if the caller does not have cross user permission + continue; + } + if (!allowed && !task.isActivityTypeHome()) { + // Skip if the caller isn't allowed to fetch this task, except for the home + // task which we always return. + continue; + } } if (ignoreActivityType != ACTIVITY_TYPE_UNDEFINED && task.getActivityType() == ignoreActivityType) { @@ -4774,7 +4801,7 @@ class ActivityStack extends ConfigurationContainer { if (!mStackSupervisor.getLaunchParamsController() .layoutTask(task, info.windowLayout, activity, source, options) && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) { - task.updateOverrideConfiguration(getRequestedOverrideBounds()); + task.setBounds(getRequestedOverrideBounds()); } task.createTask(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); return task; diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index a480fb8f110f..7a3f022d60bf 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -1398,7 +1398,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { boolean reparented = false; if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) { final Rect bounds = options.getLaunchBounds(); - task.updateOverrideConfiguration(bounds); + task.setBounds(bounds); ActivityStack stack = mRootActivityContainer.getLaunchStack(null, options, task, ON_TOP); @@ -1412,10 +1412,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // task.reparent() should already placed the task on top, // still need moveTaskToFrontLocked() below for any transition settings. } - if (stack.resizeStackWithLaunchBounds()) { - mRootActivityContainer.resizeStack(stack, bounds, null /* tempTaskBounds */, - null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, - true /* allowResizeInDockedMode */, !DEFER_RESUME); + if (stack.shouldResizeStackWithLaunchBounds()) { + stack.resize(bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, + !PRESERVE_WINDOWS, !DEFER_RESUME); } else { // WM resizeTask must be done after the task is moved to the correct stack, // because Task's setBounds() also updates dim layer's bounds, but that has @@ -1636,7 +1635,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // Don't allow re-entry while resizing. E.g. due to docked stack detaching. mAllowDockedStackResize = false; ActivityRecord r = stack.topRunningActivityLocked(); - stack.resize(dockedBounds, tempDockedTaskBounds, tempDockedTaskInsetBounds); + stack.resize(dockedBounds, tempDockedTaskBounds, tempDockedTaskInsetBounds, + !PRESERVE_WINDOWS, DEFER_RESUME); // TODO: Checking for isAttached might not be needed as if the user passes in null // dockedBounds then they want the docked stack to be dismissed. @@ -1674,11 +1674,19 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { tempRect /* outStackBounds */, otherTaskRect /* outTempTaskBounds */); - mRootActivityContainer.resizeStack(current, - !tempRect.isEmpty() ? tempRect : null, + if (tempRect.isEmpty()) { + // If this scenario is hit, it means something is not working right. + // Empty/null bounds implies fullscreen. In the event that this stack + // *should* be fullscreen, its mode should be set explicitly in a form + // of setWindowingMode so that other parts of the system are updated + // properly. + throw new IllegalArgumentException("Trying to set null bounds on a" + + " non-fullscreen stack"); + } + + current.resize(tempRect, !otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds, - tempOtherTaskInsetBounds, preserveWindows, - true /* allowResizeInDockedMode */, deferResume); + tempOtherTaskInsetBounds, preserveWindows, deferResume); } } if (!deferResume) { @@ -1728,8 +1736,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // transitioning it from fullscreen into a floating state. stack.onPipAnimationEndResize(); } - stack.resize(pinnedBounds, tempPinnedTaskBounds, insetBounds); - stack.ensureVisibleActivitiesConfigurationLocked(r, false); + stack.resize(pinnedBounds, tempPinnedTaskBounds, insetBounds, !PRESERVE_WINDOWS, + !DEFER_RESUME); } finally { mWindowManager.continueSurfaceLayout(); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 5717e2fa02d2..641b00aeb70b 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2400,11 +2400,10 @@ class ActivityStarter { } final ActivityStack stack = task.getStack(); - if (stack != null && stack.resizeStackWithLaunchBounds()) { - mService.resizeStack( - stack.mStackId, bounds, true, !PRESERVE_WINDOWS, ANIMATE, -1); + if (stack != null && stack.inPinnedWindowingMode()) { + mService.animateResizePinnedStack(stack.mStackId, bounds, -1); } else { - task.updateOverrideConfiguration(bounds); + task.setBounds(bounds); } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index ee56c0902e78..d97f0f5041a4 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -19,6 +19,8 @@ package com.android.server.wm; import static android.Manifest.permission.BIND_VOICE_INTERACTION; import static android.Manifest.permission.CHANGE_CONFIGURATION; import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; +import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; import static android.Manifest.permission.READ_FRAME_BUFFER; @@ -2508,15 +2510,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @WindowConfiguration.ActivityType int ignoreActivityType, @WindowConfiguration.WindowingMode int ignoreWindowingMode) { final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + final boolean crossUser = isCrossUserAllowed(callingPid, callingUid); ArrayList<ActivityManager.RunningTaskInfo> list = new ArrayList<>(); synchronized (mGlobalLock) { if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum); - final boolean allowed = isGetTasksAllowed("getTasks", Binder.getCallingPid(), - callingUid); + final boolean allowed = isGetTasksAllowed("getTasks", callingPid, callingUid); mRootActivityContainer.getRunningTasks(maxNum, list, ignoreActivityType, - ignoreWindowingMode, callingUid, allowed); + ignoreWindowingMode, callingUid, allowed, crossUser); } return list; @@ -2582,35 +2585,23 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override - public void resizeStack(int stackId, Rect destBounds, boolean allowResizeInDockedMode, - boolean preserveWindows, boolean animate, int animationDuration) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()"); + public void animateResizePinnedStack(int stackId, Rect destBounds, int animationDuration) { + enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "animateResizePinnedStack()"); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - if (animate) { - final ActivityStack stack = mRootActivityContainer.getStack(stackId); - if (stack == null) { - Slog.w(TAG, "resizeStack: stackId " + stackId + " not found."); - return; - } - if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) { - throw new IllegalArgumentException("Stack: " + stackId - + " doesn't support animated resize."); - } - stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds, - animationDuration, false /* fromFullscreen */); - } else { - final ActivityStack stack = mRootActivityContainer.getStack(stackId); - if (stack == null) { - Slog.w(TAG, "resizeStack: stackId " + stackId + " not found."); - return; - } - mRootActivityContainer.resizeStack(stack, destBounds, - null /* tempTaskBounds */, null /* tempTaskInsetBounds */, - preserveWindows, allowResizeInDockedMode, !DEFER_RESUME); + final ActivityStack stack = mRootActivityContainer.getStack(stackId); + if (stack == null) { + Slog.w(TAG, "resizeStack: stackId " + stackId + " not found."); + return; + } + if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) { + throw new IllegalArgumentException("Stack: " + stackId + + " doesn't support animated resize."); } + stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds, + animationDuration, false /* fromFullscreen */); } } finally { Binder.restoreCallingIdentity(ident); @@ -3546,6 +3537,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return allowed; } + boolean isCrossUserAllowed(int pid, int uid) { + return checkPermission(INTERACT_ACROSS_USERS, pid, uid) == PERMISSION_GRANTED + || checkPermission(INTERACT_ACROSS_USERS_FULL, pid, uid) == PERMISSION_GRANTED; + } + private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint, IAssistDataReceiver receiver, Bundle receiverExtras, IBinder activityToken, boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout, diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java index 59c02f736513..59df09be1ff5 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsController.java +++ b/services/core/java/com/android/server/wm/LaunchParamsController.java @@ -152,7 +152,7 @@ class LaunchParamsController { if (task.getStack().inFreeformWindowingMode()) { // Only set bounds if it's in freeform mode. - task.updateOverrideConfiguration(mTmpParams.mBounds); + task.setBounds(mTmpParams.mBounds); return true; } diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index eb5d096aa781..50b5902e17d4 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -27,12 +27,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; -import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY; @@ -93,7 +91,6 @@ import android.os.FactoryTest; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; -import android.os.Trace; import android.os.UserHandle; import android.os.storage.StorageManager; import android.provider.Settings; @@ -881,48 +878,6 @@ class RootActivityContainer extends ConfigurationContainer } } - void resizeStack(ActivityStack stack, Rect bounds, Rect tempTaskBounds, - Rect tempTaskInsetBounds, boolean preserveWindows, boolean allowResizeInDockedMode, - boolean deferResume) { - - if (stack.inSplitScreenPrimaryWindowingMode()) { - mStackSupervisor.resizeDockedStackLocked(bounds, tempTaskBounds, - tempTaskInsetBounds, null, null, preserveWindows, deferResume); - return; - } - - final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenPrimaryStack(); - if (!allowResizeInDockedMode - && !stack.getWindowConfiguration().tasksAreFloating() && splitScreenActive) { - // If the docked stack exists, don't resize non-floating stacks independently of the - // size computed from the docked stack size (otherwise they will be out of sync) - return; - } - - Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stack.mStackId); - mWindowManager.deferSurfaceLayout(); - try { - if (stack.affectedBySplitScreenResize()) { - if (bounds == null && stack.inSplitScreenWindowingMode()) { - // null bounds = fullscreen windowing mode...at least for now. - stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - } else if (splitScreenActive) { - // If we are in split-screen mode and this stack support split-screen, then - // it should be split-screen secondary mode. i.e. adjacent to the docked stack. - stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - } - } - stack.resize(bounds, tempTaskBounds, tempTaskInsetBounds); - if (!deferResume) { - stack.ensureVisibleActivitiesConfigurationLocked( - stack.topRunningActivityLocked(), preserveWindows); - } - } finally { - mWindowManager.continueSurfaceLayout(); - Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); - } - } - /** * Move stack with all its existing content to specified display. * @param stackId Id of stack to move. @@ -1014,9 +969,8 @@ class RootActivityContainer extends ConfigurationContainer // Resize the pinned stack to match the current size of the task the activity we are // going to be moving is currently contained in. We do this to have the right starting // animation bounds for the pinned stack to the desired bounds the caller wants. - resizeStack(stack, task.getRequestedOverrideBounds(), null /* tempTaskBounds */, - null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, - true /* allowResizeInDockedMode */, !DEFER_RESUME); + stack.resize(task.getRequestedOverrideBounds(), null /* tempTaskBounds */, + null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, !DEFER_RESUME); if (task.mActivities.size() == 1) { // Defer resume until below, and do not schedule PiP changes until we animate below @@ -2260,9 +2214,9 @@ class RootActivityContainer extends ConfigurationContainer void getRunningTasks(int maxNum, List<ActivityManager.RunningTaskInfo> list, @WindowConfiguration.ActivityType int ignoreActivityType, @WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid, - boolean allowed) { + boolean allowed, boolean crossUser) { mStackSupervisor.getRunningTasks().getTasks(maxNum, list, ignoreActivityType, - ignoreWindowingMode, mActivityDisplays, callingUid, allowed); + ignoreWindowingMode, mActivityDisplays, callingUid, allowed, crossUser); } void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) { diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java index 3bf437d38bcc..22a9c32a830f 100644 --- a/services/core/java/com/android/server/wm/RunningTasks.java +++ b/services/core/java/com/android/server/wm/RunningTasks.java @@ -40,7 +40,7 @@ class RunningTasks { void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType, @WindowingMode int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays, - int callingUid, boolean allowed) { + int callingUid, boolean allowed, boolean crossUser) { // Return early if there are no tasks to fetch if (maxNum <= 0) { return; @@ -55,7 +55,7 @@ class RunningTasks { final ActivityStack stack = display.getChildAt(stackNdx); mTmpStackTasks.clear(); stack.getRunningTasks(mTmpStackTasks, ignoreActivityType, ignoreWindowingMode, - callingUid, allowed); + callingUid, allowed, crossUser); mTmpSortedSet.addAll(mTmpStackTasks); } } diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index e25ca73e457d..d3f3981625d9 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -512,7 +512,7 @@ class TaskRecord extends ConfigurationContainer { if (!getWindowConfiguration().persistTaskBounds()) { // Reset current bounds for task whose bounds shouldn't be persisted so it uses // default configuration the next time it launches. - updateOverrideConfiguration(null); + setBounds(null); } mService.getTaskChangeNotificationController().notifyTaskRemoved(taskId); } @@ -565,7 +565,7 @@ class TaskRecord extends ConfigurationContainer { // Task doesn't exist in window manager yet (e.g. was restored from recents). // All we can do for now is update the bounds so it can be used when the task is // added to window manager. - updateOverrideConfiguration(bounds); + setBounds(bounds); if (!inFreeformWindowingMode()) { // re-restore the task so it can have the proper stack association. mService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP); @@ -584,7 +584,11 @@ class TaskRecord extends ConfigurationContainer { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + taskId); - final boolean updatedConfig = updateOverrideConfiguration(bounds); + boolean updatedConfig = false; + mTmpConfig.setTo(getResolvedOverrideConfiguration()); + if (setBounds(bounds) != BOUNDS_CHANGE_NONE) { + updatedConfig = !mTmpConfig.equals(getResolvedOverrideConfiguration()); + } // This variable holds information whether the configuration didn't change in a significant // way and the activity was kept the way it was. If it's false, it means the activity @@ -1803,15 +1807,6 @@ class TaskRecord extends ConfigurationContainer { } } - /** - * Update task's override configuration based on the bounds. - * @param bounds The bounds of the task. - * @return True if the override configuration was updated. - */ - boolean updateOverrideConfiguration(Rect bounds) { - return updateOverrideConfiguration(bounds, null /* insetBounds */); - } - void setLastNonFullscreenBounds(Rect bounds) { if (mLastNonFullscreenBounds == null) { mLastNonFullscreenBounds = new Rect(bounds); @@ -1821,32 +1816,6 @@ class TaskRecord extends ConfigurationContainer { } /** - * Update task's override configuration based on the bounds. - * @param bounds The bounds of the task. - * @param insetBounds The bounds used to calculate the system insets, which is used here to - * subtract the navigation bar/status bar size from the screen size reported - * to the application. See {@link IActivityTaskManager#resizeDockedStack}. - * @return True if the override configuration was updated. - */ - boolean updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) { - final boolean hasSetDisplayedBounds = (insetBounds != null && !insetBounds.isEmpty()); - if (hasSetDisplayedBounds) { - setDisplayedBounds(bounds); - } else { - setDisplayedBounds(null); - } - // "steady" bounds do not include any temporary offsets from animation or interaction. - Rect steadyBounds = hasSetDisplayedBounds ? insetBounds : bounds; - if (equivalentRequestedOverrideBounds(steadyBounds)) { - return false; - } - - mTmpConfig.setTo(getResolvedOverrideConfiguration()); - setBounds(steadyBounds); - return !mTmpConfig.equals(getResolvedOverrideConfiguration()); - } - - /** * This should be called when an child activity changes state. This should only * be called from * {@link ActivityRecord#setState(ActivityState, String)} . @@ -2297,7 +2266,7 @@ class TaskRecord extends ConfigurationContainer { Rect updateOverrideConfigurationFromLaunchBounds() { final Rect bounds = getLaunchBounds(); - updateOverrideConfiguration(bounds); + setBounds(bounds); if (bounds != null && !bounds.isEmpty()) { // TODO: Review if we actually want to do this - we are setting the launch bounds // directly here. @@ -2322,12 +2291,12 @@ class TaskRecord extends ConfigurationContainer { return; } if (mLastNonFullscreenBounds != null) { - updateOverrideConfiguration(mLastNonFullscreenBounds); + setBounds(mLastNonFullscreenBounds); } else { mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null); } } else { - updateOverrideConfiguration(inStack.getRequestedOverrideBounds()); + setBounds(inStack.getRequestedOverrideBounds()); } } diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 814bec671750..bef6a37a1ebe 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -859,7 +859,7 @@ public class TaskStack extends WindowContainer<Task> implements // When the home stack is resizable, should always have the same stack and task bounds if (isActivityTypeHome()) { final Task homeTask = findHomeTask(); - if (homeTask != null && homeTask.isResizeable()) { + if (homeTask == null || homeTask.isResizeable()) { // Calculate the home stack bounds when in docked mode and the home stack is // resizeable. getDisplayContent().mDividerControllerLocked @@ -965,7 +965,7 @@ public class TaskStack extends WindowContainer<Task> implements } void resetDockedStackToMiddle() { - if (inSplitScreenPrimaryWindowingMode()) { + if (!inSplitScreenPrimaryWindowingMode()) { throw new IllegalStateException("Not a docked stack=" + this); } @@ -973,12 +973,12 @@ public class TaskStack extends WindowContainer<Task> implements final Rect bounds = new Rect(); final Rect tempBounds = new Rect(); - TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility(); - Rect dockedBounds = - (dockedStack == null || dockedStack == this) ? null : dockedStack.getRawBounds(); - getStackDockedModeBoundsLocked(mDisplayContent.getConfiguration(), dockedBounds, + getStackDockedModeBoundsLocked(mDisplayContent.getConfiguration(), null /* dockedBounds */, null /* currentTempTaskBounds */, bounds, tempBounds); - mActivityStack.requestResize(bounds); + mActivityStack.mStackSupervisor.resizeDockedStackLocked(bounds, null /* tempTaskBounds */, + null /* tempTaskInsetBounds */, null /* tempOtherTaskBounds */, + null /* tempOtherTaskInsetBounds */, false /* preserveWindows */, + false /* deferResume */); } @Override diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml index 7453c489ecc8..180deb5c4dcc 100644 --- a/services/tests/uiservicestests/AndroidManifest.xml +++ b/services/tests/uiservicestests/AndroidManifest.xml @@ -31,6 +31,7 @@ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" /> <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/> + <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> diff --git a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java index 14b71ec526a8..3c2d55058c3e 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java +++ b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java @@ -27,9 +27,11 @@ import androidx.test.InstrumentationRegistry; import com.android.server.uri.UriGrantsManagerInternal; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; public class UiServiceTestCase { @@ -77,4 +79,9 @@ public class UiServiceTestCase { when(mUgmInternal.checkGrantUriPermission( anyInt(), anyString(), any(Uri.class), anyInt(), anyInt())).thenReturn(-1); } + + @After + public final void cleanUpMockito() { + Mockito.framework().clearInlineMocks(); + } } 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 be638a9d9755..d11995a82229 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -62,6 +62,7 @@ import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; @@ -209,9 +210,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { private AudioManager mAudioManager; @Mock ActivityManager mActivityManager; - NotificationManagerService.WorkerHandler mHandler; @Mock Resources mResources; + @Mock + RankingHandler mRankingHandler; private NotificationChannel mTestNotificationChannel = new NotificationChannel( TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); @@ -342,7 +344,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Use this testable looper. mTestableLooper = TestableLooper.get(this); - mHandler = mService.new WorkerHandler(mTestableLooper.getLooper()); // MockPackageManager - default returns ApplicationInfo with matching calling UID mContext.setMockPackageManager(mPackageManagerClient); @@ -391,7 +392,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true); - mService.init(mTestableLooper.getLooper(), + mService.init(mTestableLooper.getLooper(), mRankingHandler, mPackageManager, mPackageManagerClient, mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, @@ -410,6 +411,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel))); assertNotNull(mBinderService.getNotificationChannel( PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID)); + clearInvocations(mRankingHandler); } @After @@ -461,7 +463,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { Notification.Builder nb = new Notification.Builder(mContext, "a") .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, uid, "tag", uid, 0, + StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, uid, + "tag" + System.currentTimeMillis(), uid, 0, nb.build(), new UserHandle(userId), null, postTime); return sbn; } @@ -482,7 +485,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { if (isBubble) { nb.setBubbleMetadata(getBasicBubbleMetadataBuilder().build()); } - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", mUid, 0, + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, + "tag" + System.currentTimeMillis(), mUid, 0, nb.build(), new UserHandle(mUid), null, 0); return new NotificationRecord(mContext, sbn, channel); } @@ -510,7 +515,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { if (isBubble) { nb.setBubbleMetadata(getBasicBubbleMetadataBuilder().build()); } - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", mUid, 0, + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); return new NotificationRecord(mContext, sbn, channel); } @@ -588,7 +593,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mActivityManager.getPackageImportance(nrBubble.sbn.getPackageName())).thenReturn( IMPORTANCE_FOREGROUND); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nrBubble.sbn.getTag(), nrBubble.sbn.getId(), nrBubble.sbn.getNotification(), nrBubble.sbn.getUserId()); waitForIdle(); @@ -600,7 +605,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Plain notification without bubble metadata NotificationRecord nrPlain = generateNotificationRecord(mTestNotificationChannel, 2, "BUBBLE_GROUP", false /* isSummary */, false /* isBubble */); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nrPlain.sbn.getTag(), nrPlain.sbn.getId(), nrPlain.sbn.getNotification(), nrPlain.sbn.getUserId()); waitForIdle(); @@ -613,7 +618,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { if (summaryAutoCancel) { nrSummary.getNotification().flags |= FLAG_AUTO_CANCEL; } - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nrSummary.sbn.getTag(), nrSummary.sbn.getId(), nrSummary.sbn.getNotification(), nrSummary.sbn.getUserId()); waitForIdle(); @@ -757,7 +762,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mBinderService.createNotificationChannels( PKG, new ParceledListSlice(Arrays.asList(channel))); final StatusBarNotification sbn = generateNotificationRecord(channel).sbn; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testBlockedNotifications_blockedChannel", sbn.getId(), sbn.getNotification(), sbn.getUserId()); waitForIdle(); assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); @@ -775,7 +781,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final StatusBarNotification sbn = generateNotificationRecord(channel).sbn; sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId()); waitForIdle(); assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length); @@ -804,7 +810,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { StatusBarNotification sbn = generateNotificationRecord(channel).sbn; sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId()); waitForIdle(); // The first time a foreground service notification is shown, we allow the channel @@ -826,7 +832,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { sbn = generateNotificationRecord(channel).sbn; sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testEnqueuedBlockedNotifications_userBlockedChannelForegroundService", sbn.getId(), sbn.getNotification(), sbn.getUserId()); waitForIdle(); // The second time it is shown, we keep the user's preference. @@ -840,7 +847,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testBlockedNotifications_blockedChannelGroup() throws Exception { when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); mService.setPreferencesHelper(mPreferencesHelper); - when(mPreferencesHelper.isGroupBlocked(anyString(), anyInt(), anyString())).thenReturn(true); + when(mPreferencesHelper.isGroupBlocked(anyString(), anyInt(), anyString())). + thenReturn(true); NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH); @@ -857,7 +865,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false); final StatusBarNotification sbn = generateNotificationRecord(null).sbn; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testEnqueuedBlockedNotifications_blockedApp", sbn.getId(), sbn.getNotification(), sbn.getUserId()); waitForIdle(); assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); @@ -871,7 +880,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testEnqueuedBlockedNotifications_blockedAppForegroundService", sbn.getId(), sbn.getNotification(), sbn.getUserId()); waitForIdle(); assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); @@ -893,7 +903,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn; sbn.getNotification().category = category; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testEnqueuedRestrictedNotifications_asSystem", sbn.getId(), sbn.getNotification(), sbn.getUserId()); } waitForIdle(); @@ -917,7 +928,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn; sbn.getNotification().category = category; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testEnqueuedRestrictedNotifications_notAutomotive", sbn.getId(), sbn.getNotification(), sbn.getUserId()); } waitForIdle(); @@ -940,7 +952,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; sbn.getNotification().category = category; try { - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testEnqueuedRestrictedNotifications_badUser", sbn.getId(), sbn.getNotification(), sbn.getUserId()); fail("Calls from non system apps should not allow use of restricted categories"); } catch (SecurityException e) { @@ -977,7 +990,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception { - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0, + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, generateNotificationRecord(null).getNotification(), 0); waitForIdle(); StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG); @@ -987,9 +1001,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception { - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0, + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelNotificationImmediatelyAfterEnqueue", 0, generateNotificationRecord(null).getNotification(), 0); - mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", 0, 0); + mBinderService.cancelNotificationWithTag(PKG, PKG, + "testCancelNotificationImmediatelyAfterEnqueue", 0, 0); waitForIdle(); StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG); @@ -999,12 +1015,15 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testCancelNotificationWhilePostedAndEnqueued() throws Exception { - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0, + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelNotificationWhilePostedAndEnqueued", 0, generateNotificationRecord(null).getNotification(), 0); waitForIdle(); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0, + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelNotificationWhilePostedAndEnqueued", 0, generateNotificationRecord(null).getNotification(), 0); - mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", 0, 0); + mBinderService.cancelNotificationWithTag(PKG, PKG, + "testCancelNotificationWhilePostedAndEnqueued", 0, 0); waitForIdle(); StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG); @@ -1019,7 +1038,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception { NotificationRecord r = generateNotificationRecord(null); final StatusBarNotification sbn = r.sbn; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelNotificationsFromListenerImmediatelyAfterEnqueue", sbn.getId(), sbn.getNotification(), sbn.getUserId()); mBinderService.cancelNotificationsFromListener(null, null); waitForIdle(); @@ -1032,7 +1052,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelAllNotificationsImmediatelyAfterEnqueue", sbn.getId(), sbn.getNotification(), sbn.getUserId()); mBinderService.cancelAllNotifications(PKG, sbn.getUserId()); waitForIdle(); @@ -1047,7 +1068,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final NotificationRecord n = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testUserInitiatedClearAll_noLeak", n.sbn.getId(), n.sbn.getNotification(), n.sbn.getUserId()); waitForIdle(); @@ -1070,9 +1092,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final NotificationRecord child = generateNotificationRecord( mTestNotificationChannel, 2, "group1", false); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelAllNotificationsCancelsChildren", parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId()); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelAllNotificationsCancelsChildren", child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId()); waitForIdle(); @@ -1085,7 +1109,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; for (int i = 0; i < 10; i++) { - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelAllNotificationsMultipleEnqueuedDoesNotCrash", sbn.getId(), sbn.getNotification(), sbn.getUserId()); } mBinderService.cancelAllNotifications(PKG, sbn.getUserId()); @@ -1104,17 +1129,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mTestNotificationChannel, 2, "group1", false); // fully post parent notification - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId()); waitForIdle(); // enqueue the child several times for (int i = 0; i < 10; i++) { - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId()); } // make the parent a child, which will cancel the child notification - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", parentAsChild.sbn.getId(), parentAsChild.sbn.getNotification(), parentAsChild.sbn.getUserId()); waitForIdle(); @@ -1126,7 +1154,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testCancelAllNotifications_IgnoreForegroundService() throws Exception { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelAllNotifications_IgnoreForegroundService", sbn.getId(), sbn.getNotification(), sbn.getUserId()); mBinderService.cancelAllNotifications(PKG, sbn.getUserId()); waitForIdle(); @@ -1140,7 +1169,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelAllNotifications_IgnoreOtherPackages", sbn.getId(), sbn.getNotification(), sbn.getUserId()); mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId()); waitForIdle(); @@ -1153,7 +1183,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelAllNotifications_NullPkgRemovesAll", sbn.getId(), sbn.getNotification(), sbn.getUserId()); mBinderService.cancelAllNotifications(null, sbn.getUserId()); waitForIdle(); @@ -1166,7 +1197,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testCancelAllNotifications_NullPkgIgnoresUserAllNotifications", sbn.getId(), sbn.getNotification(), UserHandle.USER_ALL); // Null pkg is how we signal a user switch. mBinderService.cancelAllNotifications(null, sbn.getUserId()); @@ -1181,7 +1213,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testAppInitiatedCancelAllNotifications_CancelsNoClearFlag() throws Exception { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; sbn.getNotification().flags |= Notification.FLAG_NO_CLEAR; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testAppInitiatedCancelAllNotifications_CancelsNoClearFlag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); mBinderService.cancelAllNotifications(PKG, sbn.getUserId()); waitForIdle(); @@ -1266,7 +1299,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception { - final StatusBarNotification sbn = generateNotificationRecord(null).sbn; + Notification n = + new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .build(); + StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0, + n, new UserHandle(mUid), null, 0); sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; mBinderService.enqueueNotificationWithTag(PKG, PKG, null, sbn.getId(), sbn.getNotification(), sbn.getUserId()); @@ -1283,12 +1321,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId()); sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId()); - mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getUserId()); + mBinderService.cancelNotificationWithTag(PKG, PKG, sbn.getTag(), sbn.getId(), + sbn.getUserId()); waitForIdle(); assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); assertEquals(0, mService.getNotificationRecordCount()); @@ -1376,21 +1415,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // should not be returned final NotificationRecord group2 = generateNotificationRecord( mTestNotificationChannel, 2, "group2", true); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testFindGroupNotificationsLocked", group2.sbn.getId(), group2.sbn.getNotification(), group2.sbn.getUserId()); waitForIdle(); // should not be returned final NotificationRecord nonGroup = generateNotificationRecord( mTestNotificationChannel, 3, null, false); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testFindGroupNotificationsLocked", nonGroup.sbn.getId(), nonGroup.sbn.getNotification(), nonGroup.sbn.getUserId()); waitForIdle(); // same group, child, should be returned final NotificationRecord group1Child = generateNotificationRecord( mTestNotificationChannel, 4, "group1", false); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, group1Child.sbn.getId(), + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testFindGroupNotificationsLocked", + group1Child.sbn.getId(), group1Child.sbn.getNotification(), group1Child.sbn.getUserId()); waitForIdle(); @@ -1447,7 +1487,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag() throws Exception { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); mBinderService.cancelAllNotifications(PKG, sbn.getUserId()); waitForIdle(); @@ -1564,7 +1605,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { new NotificationChannel("foo", "foo", IMPORTANCE_HIGH)); Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo"); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0, + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testTvExtenderChannelOverride_onTv", 0, generateNotificationRecord(null, tv).getNotification(), 0); verify(mPreferencesHelper, times(1)).getNotificationChannel( anyString(), anyInt(), eq("foo"), anyBoolean()); @@ -1579,8 +1620,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mTestNotificationChannel); Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo"); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0, - generateNotificationRecord(null, tv).getNotification(), 0); + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testTvExtenderChannelOverride_notOnTv", + 0, generateNotificationRecord(null, tv).getNotification(), 0); verify(mPreferencesHelper, times(1)).getNotificationChannel( anyString(), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean()); } @@ -2220,7 +2261,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final NotificationRecord child = generateNotificationRecord( mTestNotificationChannel, 2, "group", false); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testPostNonGroup_noUnsnoozing", child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId()); waitForIdle(); @@ -2233,7 +2274,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final NotificationRecord record = generateNotificationRecord( mTestNotificationChannel, 2, null, false); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testPostNonGroup_noUnsnoozing", record.sbn.getId(), record.sbn.getNotification(), record.sbn.getUserId()); waitForIdle(); @@ -2245,7 +2286,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 2, "group", true); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, "testPostGroupSummary_noUnsnoozing", parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId()); waitForIdle(); @@ -2659,31 +2700,37 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setColorized(true) .setFlag(Notification.FLAG_CAN_COLORIZE, true) .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", mUid, 0, + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testNoFakeColorizedPermission", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); NotificationRecord posted = mService.findNotificationLocked( - PKG, null, nr.sbn.getId(), nr.sbn.getUserId()); + PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getUserId()); assertFalse(posted.getNotification().isColorized()); } @Test - public void testGetNotificationCountLocked() throws Exception { + public void testGetNotificationCountLocked() { + String sampleTagToExclude = null; + int sampleIdToExclude = 0; for (int i = 0; i < 20; i++) { NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, null, false); mService.addEnqueuedNotification(r); + } for (int i = 0; i < 20; i++) { NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, null, false); mService.addNotification(r); + sampleTagToExclude = r.sbn.getTag(); + sampleIdToExclude = i; } // another package @@ -2700,55 +2747,49 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addNotification(otherPackage); // Same notifications are enqueued as posted, everything counts b/c id and tag don't match + // anything that's currently enqueued or posted int userId = new UserHandle(mUid).getIdentifier(); assertEquals(40, mService.getNotificationCountLocked(PKG, userId, 0, null)); assertEquals(40, mService.getNotificationCountLocked(PKG, userId, 0, "tag2")); + + // return all for package "a" - "banana" tag isn't used assertEquals(2, mService.getNotificationCountLocked("a", userId, 0, "banana")); // exclude a known notification - it's excluded from only the posted list, not enqueued - assertEquals(39, - mService.getNotificationCountLocked(PKG, userId, 0, "tag")); + assertEquals(39, mService.getNotificationCountLocked( + PKG, userId, sampleIdToExclude, sampleTagToExclude)); } @Test public void testAddAutogroup_requestsSort() throws Exception { - RankingHandler rh = mock(RankingHandler.class); - mService.setRankingHandler(rh); - final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addNotification(r); mService.addAutogroupKeyLocked(r.getKey()); - verify(rh, times(1)).requestSort(); + verify(mRankingHandler, times(1)).requestSort(); } @Test public void testRemoveAutogroup_requestsSort() throws Exception { - RankingHandler rh = mock(RankingHandler.class); - mService.setRankingHandler(rh); - final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); r.setOverrideGroupKey("TEST"); mService.addNotification(r); mService.removeAutogroupKeyLocked(r.getKey()); - verify(rh, times(1)).requestSort(); + verify(mRankingHandler, times(1)).requestSort(); } @Test public void testReaddAutogroup_noSort() throws Exception { - RankingHandler rh = mock(RankingHandler.class); - mService.setRankingHandler(rh); - final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); r.setOverrideGroupKey("TEST"); mService.addNotification(r); mService.addAutogroupKeyLocked(r.getKey()); - verify(rh, never()).requestSort(); + verify(mRankingHandler, never()).requestSort(); } @Test @@ -2922,7 +2963,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setFlag(FLAG_FOREGROUND_SERVICE, true) .setPriority(Notification.PRIORITY_MIN); - StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", + StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, + "testBumpFGImportance_noChannelChangePreOApp", Binder.getCallingUid(), 0, nb.build(), new UserHandle(Binder.getCallingUid()), null, 0); mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(), @@ -2938,10 +2980,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setFlag(FLAG_FOREGROUND_SERVICE, true) .setPriority(Notification.PRIORITY_MIN); - sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", Binder.getCallingUid(), + sbn = new StatusBarNotification(preOPkg, preOPkg, 9, + "testBumpFGImportance_noChannelChangePreOApp", Binder.getCallingUid(), 0, nb.build(), new UserHandle(Binder.getCallingUid()), null, 0); - mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, "tag", + mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, + "testBumpFGImportance_noChannelChangePreOApp", sbn.getId(), sbn.getNotification(), sbn.getUserId()); waitForIdle(); assertEquals(IMPORTANCE_LOW, @@ -3154,9 +3198,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testUserSentimentChangeTriggersUpdate() throws Exception { final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addNotification(r); - NotificationManagerService.WorkerHandler handler = mock( - NotificationManagerService.WorkerHandler.class); - mService.setHandler(handler); when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); Bundle signals = new Bundle(); @@ -3168,16 +3209,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { waitForIdle(); - verify(handler, timeout(300).times(1)).scheduleSendRankingUpdate(); + verify(mRankingHandler, timeout(300).times(1)).requestSort(); } @Test public void testTooLateAdjustmentTriggersUpdate() throws Exception { final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addNotification(r); - NotificationManagerService.WorkerHandler handler = mock( - NotificationManagerService.WorkerHandler.class); - mService.setHandler(handler); when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); Bundle signals = new Bundle(); @@ -3189,16 +3227,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { waitForIdle(); - verify(handler, timeout(300).times(1)).scheduleSendRankingUpdate(); + verify(mRankingHandler, times(1)).requestSort(); } @Test public void testEnqueuedAdjustmentAppliesAdjustments() throws Exception { final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addEnqueuedNotification(r); - NotificationManagerService.WorkerHandler handler = mock( - NotificationManagerService.WorkerHandler.class); - mService.setHandler(handler); when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); Bundle signals = new Bundle(); @@ -3208,8 +3243,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { r.sbn.getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); - assertEquals(USER_SENTIMENT_NEGATIVE, - r.getUserSentiment()); + assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment()); } @Test @@ -4099,7 +4133,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final StatusBarNotification sbn = generateNotificationRecord(null).sbn; try { - mInternalService.enqueueNotification(notReal, "android", 0, 0, "tag", + mInternalService.enqueueNotification(notReal, "android", 0, 0, + "testPostFromAndroidForNonExistentPackage", sbn.getId(), sbn.getNotification(), sbn.getUserId()); fail("can't post notifications for nonexistent packages, even if you exist"); } catch (SecurityException e) { @@ -4373,7 +4408,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addNotification(r); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", mUid, 0, + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, r.sbn.getId(), + r.sbn.getTag(), mUid, 0, new Notification.Builder(mContext, mTestNotificationChannel.getId()).build(), new UserHandle(mUid), null, 0); NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); @@ -4502,7 +4538,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn( IMPORTANCE_FOREGROUND); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4526,7 +4562,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn( IMPORTANCE_FOREGROUND); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4550,8 +4586,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn( IMPORTANCE_FOREGROUND); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", - nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); + mBinderService.enqueueNotificationWithTag(PKG, PKG, + nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); // yes allowed, yes foreground, yes bubble @@ -4572,7 +4608,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn( IMPORTANCE_VISIBLE); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4593,7 +4629,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Send notif when we're foreground when(mActivityManager.getPackageImportance(nr1.sbn.getPackageName())).thenReturn( IMPORTANCE_FOREGROUND); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr1.sbn.getTag(), nr1.sbn.getId(), nr1.sbn.getNotification(), nr1.sbn.getUserId()); waitForIdle(); @@ -4607,7 +4643,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mActivityManager.getPackageImportance(nr2.sbn.getPackageName())).thenReturn( IMPORTANCE_VISIBLE); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr2.sbn.getTag(), nr2.sbn.getId(), nr2.sbn.getNotification(), nr2.sbn.getUserId()); waitForIdle(); @@ -4633,7 +4669,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Send notif when we're foreground when(mActivityManager.getPackageImportance(nr1.sbn.getPackageName())).thenReturn( IMPORTANCE_FOREGROUND); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr1.sbn.getTag(), nr1.sbn.getId(), nr1.sbn.getNotification(), nr1.sbn.getUserId()); waitForIdle(); @@ -4642,7 +4678,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { nr1.sbn.getKey()).getNotification().isBubbleNotification()); // Remove the bubble - mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", nr1.sbn.getId(), + mBinderService.cancelNotificationWithTag(PKG, PKG, nr1.sbn.getTag(), nr1.sbn.getId(), nr1.sbn.getUserId()); waitForIdle(); @@ -4656,7 +4692,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mActivityManager.getPackageImportance(nr2.sbn.getPackageName())).thenReturn( IMPORTANCE_VISIBLE); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr2.sbn.getTag(), nr2.sbn.getId(), nr2.sbn.getNotification(), nr2.sbn.getUserId()); waitForIdle(); @@ -4702,11 +4738,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setActions(replyAction) .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0, + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testFlagBubbleNotifs_flag_messaging", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4735,13 +4772,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setBubbleMetadata(data) .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0, + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testFlagBubbleNotifs_flag_phonecall", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); // Make sure it has foreground service sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4774,7 +4812,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { nb.build(), new UserHandle(mUid), null, 0); NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4798,13 +4836,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setBubbleMetadata(data) .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0, + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testFlagBubbleNotifs_noFlag_phonecall_noPerson", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); // Make sure it has foreground service sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4832,13 +4871,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setBubbleMetadata(data) .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0, + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testFlagBubbleNotifs_noFlag_phonecall_noCategory", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); // Make sure it has foreground service sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4872,12 +4912,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { ) .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0, + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testFlagBubbleNotifs_noFlag_messaging_appNotAllowed", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); // Post the notification - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4895,7 +4936,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); // Post the notification - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4929,12 +4970,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { ) .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0, + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); // Post the notification - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4963,13 +5005,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setBubbleMetadata(data) .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0, + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testFlagBubbleNotifs_noFlag_phonecall_notAllowed", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); // Make sure it has foreground service sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -4998,13 +5041,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setBubbleMetadata(data) .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0, + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testFlagBubbleNotifs_noFlag_phonecall_channelNotAllowed", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); // Make sure it has foreground service sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -5033,7 +5077,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { nrBubble.sbn.getNotification().flags |= FLAG_BUBBLE; // Post the notification - mBinderService.enqueueNotificationWithTag(PKG, PKG, null, + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testAppCancelNotifications_cancelsBubbles", nrBubble.sbn.getId(), nrBubble.sbn.getNotification(), nrBubble.sbn.getUserId()); waitForIdle(); @@ -5041,7 +5086,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(1, notifs.length); assertEquals(1, mService.getNotificationRecordCount()); - mBinderService.cancelNotificationWithTag(PKG, PKG, null, nrBubble.sbn.getId(), + mBinderService.cancelNotificationWithTag(PKG, PKG, + "testAppCancelNotifications_cancelsBubbles", nrBubble.sbn.getId(), nrBubble.sbn.getUserId()); waitForIdle(); @@ -5196,7 +5242,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn( IMPORTANCE_FOREGROUND); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -5226,7 +5272,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Plain notification that has bubble metadata NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, null /* tvExtender */, true /* isBubble */); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -5260,7 +5306,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Notif that is not a bubble NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, null /* tvExtender */, true /* isBubble */); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); @@ -5290,7 +5336,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Plain notification that has bubble metadata NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, null /* tvExtender */, true /* isBubble */); - mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(), nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId()); waitForIdle(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java index f37ff1177fe9..7f9f489c509a 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java @@ -129,7 +129,7 @@ public class RoleObserverTest extends UiServiceTestCase { mRoleObserver = mService.new RoleObserver(mRoleManager, mPm, mExecutor); try { - mService.init(mock(Looper.class), + mService.init(mock(Looper.class), mock(RankingHandler.class), mock(IPackageManager.class), mock(PackageManager.class), mock(LightsManager.class), mock(NotificationListeners.class), mock(NotificationAssistants.class), diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index d2af18e5f10b..34cc0c742005 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -147,8 +147,8 @@ public class ActivityStarterTests extends ActivityTestsBase { assertThat((Object) task2.getStack()).isInstanceOf(ActivityStack.class); mStarter.updateBounds(task2, bounds); - verify(mService, times(1)).resizeStack(eq(task2.getStack().mStackId), - eq(bounds), anyBoolean(), anyBoolean(), anyBoolean(), anyInt()); + verify(mService, times(1)).animateResizePinnedStack(eq(task2.getStack().mStackId), + eq(bounds), anyInt()); // In the case of no animation, the stack and task bounds should be set immediately. if (!ANIMATE) { diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index fb4e330f06ed..55011fb0aa04 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -1031,7 +1031,7 @@ public class RecentTasksTest extends ActivityTestsBase { assertSecurityException(expectCallable, () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect())); assertSecurityException(expectCallable, - () -> mService.resizeStack(INVALID_STACK_ID, new Rect(), true, true, true, 0)); + () -> mService.animateResizePinnedStack(INVALID_STACK_ID, new Rect(), -1)); assertSecurityException(expectCallable, () -> mService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(), new Rect())); @@ -1289,10 +1289,10 @@ public class RecentTasksTest extends ActivityTestsBase { @Override void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType, int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays, - int callingUid, boolean allowed) { + int callingUid, boolean allowed, boolean crossUser) { mLastAllowed = allowed; super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, activityDisplays, - callingUid, allowed); + callingUid, allowed, crossUser); } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java index dc964806b7a9..cdd4c2424421 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java @@ -77,7 +77,7 @@ public class RunningTasksTest extends ActivityTestsBase { final int numFetchTasks = 5; ArrayList<RunningTaskInfo> tasks = new ArrayList<>(); mRunningTasks.getTasks(5, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED, - displays, -1 /* callingUid */, true /* allowed */); + displays, -1 /* callingUid */, true /* allowed */, true /*crossUser */); assertThat(tasks).hasSize(numFetchTasks); for (int i = 0; i < numFetchTasks; i++) { assertEquals(numTasks - i - 1, tasks.get(i).id); @@ -87,7 +87,7 @@ public class RunningTasksTest extends ActivityTestsBase { // and does not crash tasks.clear(); mRunningTasks.getTasks(100, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED, - displays, -1 /* callingUid */, true /* allowed */); + displays, -1 /* callingUid */, true /* allowed */, true /* crossUser */); assertThat(tasks).hasSize(numTasks); for (int i = 0; i < numTasks; i++) { assertEquals(numTasks - i - 1, tasks.get(i).id); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index fc464a1f4393..090623e2f767 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -121,7 +121,7 @@ public class UsageStatsService extends SystemService implements private static final long TEN_SECONDS = 10 * 1000; private static final long TWENTY_MINUTES = 20 * 60 * 1000; private static final long FLUSH_INTERVAL = COMPRESS_TIME ? TEN_SECONDS : TWENTY_MINUTES; - private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds. + static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds. private static final boolean ENABLE_KERNEL_UPDATES = true; private static final File KERNEL_COUNTER_FILE = new File("/proc/uid_procstat/set"); @@ -156,8 +156,6 @@ public class UsageStatsService extends SystemService implements private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>(); private final SparseBooleanArray mUserUnlockedStates = new SparseBooleanArray(); private final SparseIntArray mUidToKernelCounter = new SparseIntArray(); - long mRealTimeSnapshot; - long mSystemTimeSnapshot; int mUsageSource; /** Manages the standby state of apps. */ @@ -253,9 +251,6 @@ public class UsageStatsService extends SystemService implements getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, filter, null, mHandler); - mRealTimeSnapshot = SystemClock.elapsedRealtime(); - mSystemTimeSnapshot = System.currentTimeMillis(); - publishLocalService(UsageStatsManagerInternal.class, new LocalService()); publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService()); } @@ -345,7 +340,7 @@ public class UsageStatsService extends SystemService implements mUserUnlockedStates.put(userId, true); final UserUsageStatsService userService = getUserDataAndInitializeIfNeededLocked( userId, System.currentTimeMillis()); - userService.userUnlocked(checkAndGetTimeLocked()); + userService.userUnlocked(System.currentTimeMillis()); // Process all the pending reported events while (pendingEvents.peek() != null) { reportEvent(pendingEvents.poll(), userId); @@ -569,37 +564,6 @@ public class UsageStatsService extends SystemService implements } /** - * This should be the only way to get the time from the system. - */ - private long checkAndGetTimeLocked() { - final long actualSystemTime = System.currentTimeMillis(); - final long actualRealtime = SystemClock.elapsedRealtime(); - final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot; - final long diffSystemTime = actualSystemTime - expectedSystemTime; - if (Math.abs(diffSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS - && ENABLE_TIME_CHANGE_CORRECTION) { - // The time has changed. - Slog.i(TAG, "Time changed in UsageStats by " + (diffSystemTime / 1000) + " seconds"); - final int userCount = mUserState.size(); - for (int i = 0; i < userCount; i++) { - final UserUsageStatsService service = mUserState.valueAt(i); - service.onTimeChanged(expectedSystemTime, actualSystemTime); - } - mRealTimeSnapshot = actualRealtime; - mSystemTimeSnapshot = actualSystemTime; - } - return actualSystemTime; - } - - /** - * Assuming the event's timestamp is measured in milliseconds since boot, - * convert it to a system wall time. - */ - private void convertToSystemTimeLocked(Event event) { - event.mTimeStamp = Math.max(0, event.mTimeStamp - mRealTimeSnapshot) + mSystemTimeSnapshot; - } - - /** * Called by the Binder stub */ void shutdown() { @@ -718,9 +682,8 @@ public class UsageStatsService extends SystemService implements return; } - final long timeNow = checkAndGetTimeLocked(); + final long timeNow = System.currentTimeMillis(); final long elapsedRealtime = SystemClock.elapsedRealtime(); - convertToSystemTimeLocked(event); if (event.mPackage != null && mPackageManagerInternal.isPackageEphemeral(userId, event.mPackage)) { @@ -876,13 +839,8 @@ public class UsageStatsService extends SystemService implements return null; } - final long timeNow = checkAndGetTimeLocked(); - if (!validRange(timeNow, beginTime, endTime)) { - return null; - } - final UserUsageStatsService service = - getUserDataAndInitializeIfNeededLocked(userId, timeNow); + getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis()); List<UsageStats> list = service.queryUsageStats(bucketType, beginTime, endTime); if (list == null) { return null; @@ -913,13 +871,8 @@ public class UsageStatsService extends SystemService implements return null; } - final long timeNow = checkAndGetTimeLocked(); - if (!validRange(timeNow, beginTime, endTime)) { - return null; - } - final UserUsageStatsService service = - getUserDataAndInitializeIfNeededLocked(userId, timeNow); + getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis()); return service.queryConfigurationStats(bucketType, beginTime, endTime); } } @@ -935,13 +888,8 @@ public class UsageStatsService extends SystemService implements return null; } - final long timeNow = checkAndGetTimeLocked(); - if (!validRange(timeNow, beginTime, endTime)) { - return null; - } - final UserUsageStatsService service = - getUserDataAndInitializeIfNeededLocked(userId, timeNow); + getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis()); return service.queryEventStats(bucketType, beginTime, endTime); } } @@ -957,13 +905,8 @@ public class UsageStatsService extends SystemService implements return null; } - final long timeNow = checkAndGetTimeLocked(); - if (!validRange(timeNow, beginTime, endTime)) { - return null; - } - final UserUsageStatsService service = - getUserDataAndInitializeIfNeededLocked(userId, timeNow); + getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis()); return service.queryEvents(beginTime, endTime, shouldObfuscateInstantApps); } } @@ -979,21 +922,12 @@ public class UsageStatsService extends SystemService implements return null; } - final long timeNow = checkAndGetTimeLocked(); - if (!validRange(timeNow, beginTime, endTime)) { - return null; - } - final UserUsageStatsService service = - getUserDataAndInitializeIfNeededLocked(userId, timeNow); + getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis()); return service.queryEventsForPackage(beginTime, endTime, packageName, includeTaskRoot); } } - private static boolean validRange(long currentTime, long beginTime, long endTime) { - return beginTime <= currentTime && beginTime < endTime; - } - private String buildFullToken(String packageName, String token) { final StringBuilder sb = new StringBuilder(packageName.length() + token.length() + 1); sb.append(packageName); @@ -2050,8 +1984,8 @@ public class UsageStatsService extends SystemService implements // Check to ensure that only user 0's data is b/r for now if (user == UserHandle.USER_SYSTEM) { - final UserUsageStatsService userStats = - getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked()); + final UserUsageStatsService userStats = getUserDataAndInitializeIfNeededLocked( + user, System.currentTimeMillis()); return userStats.getBackupPayload(key); } else { return null; @@ -2068,8 +2002,8 @@ public class UsageStatsService extends SystemService implements } if (user == UserHandle.USER_SYSTEM) { - final UserUsageStatsService userStats = - getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked()); + final UserUsageStatsService userStats = getUserDataAndInitializeIfNeededLocked( + user, System.currentTimeMillis()); userStats.applyRestoredPayload(key, payload); } } diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 6fbd88227f9b..1560b9e708e3 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -76,6 +76,8 @@ class UserUsageStatsService { private final String mLogPrefix; private String mLastBackgroundedPackage; private final int mUserId; + private long mRealTimeSnapshot; + private long mSystemTimeSnapshot; private static final long[] INTERVAL_LENGTH = new long[] { UnixCalendar.DAY_IN_MILLIS, UnixCalendar.WEEK_IN_MILLIS, @@ -101,6 +103,8 @@ class UserUsageStatsService { mListener = listener; mLogPrefix = "User[" + Integer.toString(userId) + "] "; mUserId = userId; + mRealTimeSnapshot = SystemClock.elapsedRealtime(); + mSystemTimeSnapshot = System.currentTimeMillis(); } void init(final long currentTimeMillis) { @@ -165,12 +169,41 @@ class UserUsageStatsService { persistActiveStats(); } - void onTimeChanged(long oldTime, long newTime) { + private void onTimeChanged(long oldTime, long newTime) { persistActiveStats(); mDatabase.onTimeChanged(newTime - oldTime); loadActiveStats(newTime); } + /** + * This should be the only way to get the time from the system. + */ + private long checkAndGetTimeLocked() { + final long actualSystemTime = System.currentTimeMillis(); + if (!UsageStatsService.ENABLE_TIME_CHANGE_CORRECTION) { + return actualSystemTime; + } + final long actualRealtime = SystemClock.elapsedRealtime(); + final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot; + final long diffSystemTime = actualSystemTime - expectedSystemTime; + if (Math.abs(diffSystemTime) > UsageStatsService.TIME_CHANGE_THRESHOLD_MILLIS) { + // The time has changed. + Slog.i(TAG, mLogPrefix + "Time changed in by " + (diffSystemTime / 1000) + " seconds"); + onTimeChanged(expectedSystemTime, actualSystemTime); + mRealTimeSnapshot = actualRealtime; + mSystemTimeSnapshot = actualSystemTime; + } + return actualSystemTime; + } + + /** + * Assuming the event's timestamp is measured in milliseconds since boot, + * convert it to a system wall time. + */ + private void convertToSystemTimeLocked(Event event) { + event.mTimeStamp = Math.max(0, event.mTimeStamp - mRealTimeSnapshot) + mSystemTimeSnapshot; + } + void reportEvent(Event event) { if (DEBUG) { Slog.d(TAG, mLogPrefix + "Got usage event for " + event.mPackage @@ -178,6 +211,9 @@ class UserUsageStatsService { + eventToString(event.mEventType)); } + checkAndGetTimeLocked(); + convertToSystemTimeLocked(event); + if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) { // Need to rollover rolloverStats(event.mTimeStamp); @@ -298,6 +334,10 @@ class UserUsageStatsService { } }; + private static boolean validRange(long currentTime, long beginTime, long endTime) { + return beginTime <= currentTime && beginTime < endTime; + } + /** * Generic query method that selects the appropriate IntervalStats for the specified time range * and bucket, then calls the {@link com.android.server.usage.UsageStatsDatabase.StatCombiner} @@ -370,19 +410,31 @@ class UserUsageStatsService { } List<UsageStats> queryUsageStats(int bucketType, long beginTime, long endTime) { + if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) { + return null; + } return queryStats(bucketType, beginTime, endTime, sUsageStatsCombiner); } List<ConfigurationStats> queryConfigurationStats(int bucketType, long beginTime, long endTime) { + if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) { + return null; + } return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner); } List<EventStats> queryEventStats(int bucketType, long beginTime, long endTime) { + if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) { + return null; + } return queryStats(bucketType, beginTime, endTime, sEventStatsCombiner); } UsageEvents queryEvents(final long beginTime, final long endTime, boolean obfuscateInstantApps) { + if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) { + return null; + } final ArraySet<String> names = new ArraySet<>(); List<Event> results = queryStats(INTERVAL_DAILY, beginTime, endTime, new StatCombiner<Event>() { @@ -428,6 +480,9 @@ class UserUsageStatsService { UsageEvents queryEventsForPackage(final long beginTime, final long endTime, final String packageName, boolean includeTaskRoot) { + if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) { + return null; + } final ArraySet<String> names = new ArraySet<>(); names.add(packageName); final List<Event> results = queryStats(INTERVAL_DAILY, @@ -1030,10 +1085,12 @@ class UserUsageStatsService { } byte[] getBackupPayload(String key){ + checkAndGetTimeLocked(); return mDatabase.getBackupPayload(key); } void applyRestoredPayload(String key, byte[] payload){ + checkAndGetTimeLocked(); mDatabase.applyRestoredPayload(key, payload); } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java index de2dd101acfd..3f2d8c8ef47c 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java @@ -41,6 +41,8 @@ public final class UsbConfigDescriptor extends UsbDescriptor { // D4..0 Reserved, set to 0. private int mMaxPower; // 8:1 Maximum Power Consumption in 2mA units + private boolean mBlockAudio; // leave it off for now. We be replace with a "Developer Option" + private ArrayList<UsbInterfaceDescriptor> mInterfaceDescriptors = new ArrayList<UsbInterfaceDescriptor>(); @@ -77,21 +79,35 @@ public final class UsbConfigDescriptor extends UsbDescriptor { mInterfaceDescriptors.add(interfaceDesc); } + private boolean isAudioInterface(UsbInterfaceDescriptor descriptor) { + return descriptor.getUsbClass() == UsbDescriptor.CLASSID_AUDIO + && descriptor.getUsbSubclass() == UsbDescriptor.AUDIO_AUDIOSTREAMING; + } + UsbConfiguration toAndroid(UsbDescriptorParser parser) { if (UsbDescriptorParser.DEBUG) { Log.d(TAG, " toAndroid()"); } + + // NOTE - This code running in the server process. + //TODO (pmclean@) - remove this +// int pid = android.os.Process.myPid(); +// int uid = android.os.Process.myUid(); +// Log.d(TAG, " ---- pid:" + pid + " uid:" + uid); + String name = parser.getDescriptorString(mConfigIndex); UsbConfiguration config = new UsbConfiguration(mConfigValue, name, mAttribs, mMaxPower); - UsbInterface[] interfaces = new UsbInterface[mInterfaceDescriptors.size()]; - if (UsbDescriptorParser.DEBUG) { - Log.d(TAG, " " + mInterfaceDescriptors.size() + " interfaces."); - } - for (int index = 0; index < mInterfaceDescriptors.size(); index++) { - interfaces[index] = mInterfaceDescriptors.get(index).toAndroid(parser); + + ArrayList<UsbInterface> filteredInterfaces = new ArrayList<UsbInterface>(); + for (UsbInterfaceDescriptor descriptor : mInterfaceDescriptors) { + if (!mBlockAudio || !isAudioInterface(descriptor)) { + filteredInterfaces.add(descriptor.toAndroid(parser)); + } } - config.setInterfaces(interfaces); + UsbInterface[] interfaceArray = new UsbInterface[0]; + interfaceArray = filteredInterfaces.toArray(interfaceArray); + config.setInterfaces(interfaceArray); return config; } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java index 4f62d5a5c967..6ffbd43a7b1a 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java @@ -26,7 +26,7 @@ import java.util.ArrayList; */ public final class UsbDescriptorParser { private static final String TAG = "UsbDescriptorParser"; - public static final boolean DEBUG = false; + public static final boolean DEBUG = true; private final String mDeviceAddr; diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java index 5eb0a2f75ded..4d0cfea98630 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java @@ -31,7 +31,7 @@ public class UsbEndpointDescriptor extends UsbDescriptor { public static final int MASK_ENDPOINT_ADDRESS = 0b000000000001111; public static final int MASK_ENDPOINT_DIRECTION = (byte) 0b0000000010000000; public static final int DIRECTION_OUTPUT = 0x0000; - public static final int DIRECTION_INPUT = (byte) 0x0080; + public static final int DIRECTION_INPUT = 0x0080; public static final int MASK_ATTRIBS_TRANSTYPE = 0b00000011; public static final int TRANSTYPE_CONTROL = 0x00; @@ -85,7 +85,7 @@ public class UsbEndpointDescriptor extends UsbDescriptor { } public int getEndpointAddress() { - return mEndpointAddress; + return mEndpointAddress & MASK_ENDPOINT_ADDRESS; } public int getAttributes() { @@ -108,6 +108,10 @@ public class UsbEndpointDescriptor extends UsbDescriptor { return mSyncAddress; } + public int getDirection() { + return mEndpointAddress & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION; + } + /* package */ UsbEndpoint toAndroid(UsbDescriptorParser parser) { if (UsbDescriptorParser.DEBUG) { Log.d(TAG, "toAndroid() type:" @@ -137,11 +141,9 @@ public class UsbEndpointDescriptor extends UsbDescriptor { canvas.openList(); - int address = getEndpointAddress(); canvas.writeListItem("Address: " - + ReportCanvas.getHexString(address & UsbEndpointDescriptor.MASK_ENDPOINT_ADDRESS) - + ((address & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION) - == UsbEndpointDescriptor.DIRECTION_OUTPUT ? " [out]" : " [in]")); + + ReportCanvas.getHexString(getEndpointAddress()) + + (getDirection() == UsbEndpointDescriptor.DIRECTION_OUTPUT ? " [out]" : " [in]")); int attributes = getAttributes(); canvas.openListItem(); diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java index 1dc6069bbb0a..64dbd971cc67 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java @@ -31,7 +31,6 @@ import java.util.ArrayList; */ public class UsbInterfaceDescriptor extends UsbDescriptor { private static final String TAG = "UsbInterfaceDescriptor"; - protected int mInterfaceNumber; // 2:1 Number of Interface protected byte mAlternateSetting; // 3:1 Value used to select alternative setting protected byte mNumEndpoints; // 4:1 Number of Endpoints used for this interface @@ -73,6 +72,19 @@ public class UsbInterfaceDescriptor extends UsbDescriptor { return mNumEndpoints; } + /** + * @param index Index of desired UsbEndpointDescriptor. + * @return the UsbEndpointDescriptor descriptor at the specified index, or + * null if an invalid index. + */ + public UsbEndpointDescriptor getEndpointDescriptor(int index) { + if (index < 0 || index >= mEndpointDescriptors.size()) { + return null; + } + + return mEndpointDescriptors.get(index); + } + public int getUsbClass() { return mUsbClass; } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java index f16dec6fb670..0ff92739f8b6 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java @@ -194,7 +194,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection, if (!mFullyBound) { mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection, Context.BIND_AUTO_CREATE | Context.BIND_TREAT_LIKE_ACTIVITY - | Context.BIND_FOREGROUND_SERVICE + | Context.BIND_SCHEDULE_LIKE_TOP_APP | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser)); } diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java index 31bd34199784..902da4c0f72e 100644 --- a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java +++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java @@ -275,7 +275,8 @@ public class IorapForwardingService extends SystemService { Log.e(TAG, "connectToRemoteAndConfigure - null iorap remote. check for Log.wtf?"); return false; } - invokeRemote( () -> mIorapRemote.setTaskListener(new RemoteTaskListener()) ); + invokeRemote(mIorapRemote, + (IIorap remote) -> remote.setTaskListener(new RemoteTaskListener()) ); registerInProcessListenersLocked(); return true; @@ -323,8 +324,9 @@ public class IorapForwardingService extends SystemService { mSequenceId, intent)); } - invokeRemote(() -> - mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(), + invokeRemote(mIorapRemote, + (IIorap remote) -> + remote.onAppLaunchEvent(RequestId.nextValueForSequence(), new AppLaunchEvent.IntentStarted(mSequenceId, intent)) ); } @@ -335,8 +337,9 @@ public class IorapForwardingService extends SystemService { Log.v(TAG, String.format("AppLaunchObserver#onIntentFailed(%d)", mSequenceId)); } - invokeRemote(() -> - mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(), + invokeRemote(mIorapRemote, + (IIorap remote) -> + remote.onAppLaunchEvent(RequestId.nextValueForSequence(), new AppLaunchEvent.IntentFailed(mSequenceId)) ); } @@ -349,8 +352,9 @@ public class IorapForwardingService extends SystemService { mSequenceId, activity, temperature)); } - invokeRemote(() -> - mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(), + invokeRemote(mIorapRemote, + (IIorap remote) -> + remote.onAppLaunchEvent(RequestId.nextValueForSequence(), new AppLaunchEvent.ActivityLaunched(mSequenceId, activity, temperature)) ); } @@ -362,8 +366,9 @@ public class IorapForwardingService extends SystemService { mSequenceId, activity)); } - invokeRemote(() -> - mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(), + invokeRemote(mIorapRemote, + (IIorap remote) -> + remote.onAppLaunchEvent(RequestId.nextValueForSequence(), new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId, activity))); } @@ -375,8 +380,9 @@ public class IorapForwardingService extends SystemService { mSequenceId, activity)); } - invokeRemote(() -> - mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(), + invokeRemote(mIorapRemote, + (IIorap remote) -> + remote.onAppLaunchEvent(RequestId.nextValueForSequence(), new AppLaunchEvent.ActivityLaunchFinished(mSequenceId, activity)) ); } @@ -501,8 +507,8 @@ public class IorapForwardingService extends SystemService { mRunningJobs.put(request, params); } - if (!invokeRemote( () -> - mIorapRemote.onJobScheduledEvent(request, + if (!invokeRemote(mIorapRemote, (IIorap remote) -> + remote.onJobScheduledEvent(request, JobScheduledEvent.createIdleMaintenance( JobScheduledEvent.TYPE_START_JOB, params)) @@ -539,8 +545,8 @@ public class IorapForwardingService extends SystemService { // Notify iorapd to stop (abort) the job. if (wasTracking) { - invokeRemote(() -> - mIorapRemote.onJobScheduledEvent(RequestId.nextValueForSequence(), + invokeRemote(mIorapRemote, (IIorap remote) -> + remote.onJobScheduledEvent(RequestId.nextValueForSequence(), JobScheduledEvent.createIdleMaintenance( JobScheduledEvent.TYPE_STOP_JOB, params)) @@ -632,12 +638,17 @@ public class IorapForwardingService extends SystemService { /** Allow passing lambdas to #invokeRemote */ private interface RemoteRunnable { // TODO: run(RequestId) ? - void run() throws RemoteException; + void run(IIorap iorap) throws RemoteException; } - private static boolean invokeRemote(RemoteRunnable r) { + // Always pass in the iorap directly here to avoid data race. + private static boolean invokeRemote(IIorap iorap, RemoteRunnable r) { + if (iorap == null) { + Log.w(TAG, "IIorap went to null in this thread, drop invokeRemote."); + return false; + } try { - r.run(); + r.run(iorap); return true; } catch (RemoteException e) { // This could be a logic error (remote side returning error), which we need to fix. diff --git a/startop/view_compiler/dex_builder_test/Android.bp b/startop/view_compiler/dex_builder_test/Android.bp index 1214538e8f0d..f783aa68fe92 100644 --- a/startop/view_compiler/dex_builder_test/Android.bp +++ b/startop/view_compiler/dex_builder_test/Android.bp @@ -37,15 +37,21 @@ genrule { android_test { name: "dex-builder-test", srcs: [ + "src/android/startop/test/ApkLayoutCompilerTest.java", "src/android/startop/test/DexBuilderTest.java", "src/android/startop/test/LayoutCompilerTest.java", "src/android/startop/test/TestClass.java", ], sdk_version: "current", - data: [":generate_dex_testcases", ":generate_compiled_layout1", ":generate_compiled_layout2"], + data: [ + ":generate_dex_testcases", + ":generate_compiled_layout1", + ":generate_compiled_layout2", + ], static_libs: [ - "androidx.test.rules", - "guava", + "androidx.test.core", + "androidx.test.runner", + "junit", ], manifest: "AndroidManifest.xml", resource_dirs: ["res"], diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/ApkLayoutCompilerTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/ApkLayoutCompilerTest.java new file mode 100644 index 000000000000..230e8df1e687 --- /dev/null +++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/ApkLayoutCompilerTest.java @@ -0,0 +1,57 @@ +/* + * 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 android.startop.test; + +import android.content.Context; +import androidx.test.InstrumentationRegistry; +import android.view.View; +import dalvik.system.PathClassLoader; +import java.lang.reflect.Method; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class ApkLayoutCompilerTest { + static ClassLoader loadDexFile() throws Exception { + Context context = InstrumentationRegistry.getTargetContext(); + return new PathClassLoader(context.getCodeCacheDir() + "/compiled_view.dex", + ClassLoader.getSystemClassLoader()); + } + + @BeforeClass + public static void setup() throws Exception { + // ensure PackageManager has compiled the layouts. + Process pm = Runtime.getRuntime().exec("pm compile --compile-layouts android.startop.test"); + pm.waitFor(); + } + + @Test + public void loadAndInflateLayout1() throws Exception { + ClassLoader dex_file = loadDexFile(); + Class compiled_view = dex_file.loadClass("android.startop.test.CompiledView"); + Method layout1 = compiled_view.getMethod("layout1", Context.class, int.class); + Context context = InstrumentationRegistry.getTargetContext(); + layout1.invoke(null, context, R.layout.layout1); + } + + @Test + public void loadAndInflateLayout2() throws Exception { + ClassLoader dex_file = loadDexFile(); + Class compiled_view = dex_file.loadClass("android.startop.test.CompiledView"); + Method layout2 = compiled_view.getMethod("layout2", Context.class, int.class); + Context context = InstrumentationRegistry.getTargetContext(); + layout2.invoke(null, context, R.layout.layout2); + } +} diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java index d1fe58800bbf..6af01f6f3292 100644 --- a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java +++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java @@ -14,8 +14,11 @@ package android.startop.test; +import android.content.Context; +import androidx.test.InstrumentationRegistry; import dalvik.system.PathClassLoader; - +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import org.junit.Assert; import org.junit.Test; diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java index 3dfb20c2e524..b0cf91d5fb97 100644 --- a/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java +++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java @@ -15,11 +15,11 @@ package android.startop.test; import android.content.Context; - import androidx.test.InstrumentationRegistry; - +import android.view.View; import dalvik.system.PathClassLoader; - +import java.lang.reflect.Method; +import org.junit.Assert; import org.junit.Test; import java.lang.reflect.Method; diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index c1b8479a7f56..67b252e52db9 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -3962,6 +3962,13 @@ public final class Telephony { public static final Uri CONTENT_URI = Uri.parse("content://cellbroadcasts"); /** + * The id of the subscription which received this cell broadcast message. + * <P>Type: INTEGER</P> + * @hide + */ + public static final String SUB_ID = "sub_id"; + + /** * Message geographical scope. Valid values are: * <ul> * <li>{@link android.telephony.SmsCbMessage#GEOGRAPHICAL_SCOPE_CELL_WIDE}. meaning the @@ -4183,6 +4190,18 @@ public final class Telephony { public static final String GEOMETRIES = "geometries"; /** + * Geo-Fencing Maximum Wait Time in second. The range of the time is [0, 255]. A device + * shall allow to determine its position meeting operator policy. If the device is unable to + * determine its position meeting operator policy within the GeoFencing Maximum Wait Time, + * it shall present the alert to the user and discontinue further positioning determination + * for the alert. + * + * <P>Type: INTEGER</P> + * @hide + */ + public static final String MAXIMUM_WAIT_TIME = "maximum_wait_time"; + + /** * Query columns for instantiating {@link android.telephony.CellBroadcastMessage} objects. * @hide */ @@ -4235,7 +4254,8 @@ public final class Telephony { CMAS_CERTAINTY, RECEIVED_TIME, MESSAGE_BROADCASTED, - GEOMETRIES + GEOMETRIES, + MAXIMUM_WAIT_TIME }; } diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java index 77231d107c6a..c078764cfa24 100644 --- a/telephony/java/android/telephony/SmsCbMessage.java +++ b/telephony/java/android/telephony/SmsCbMessage.java @@ -139,6 +139,12 @@ public final class SmsCbMessage implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface MessagePriority {} + /** + * ATIS-0700041 Section 5.2.8 WAC Geo-Fencing Maximum Wait Time Table 12. + * @hide + */ + public static final int MAXIMUM_WAIT_TIME_NOT_SET = 255; + /** Format of this message (for interpretation of service category values). */ private final int mMessageFormat; @@ -187,6 +193,14 @@ public final class SmsCbMessage implements Parcelable { @Nullable private final SmsCbCmasInfo mCmasWarningInfo; + /** + * Geo-Fencing Maximum Wait Time in second, a device shall allow to determine its position + * meeting operator policy. If the device is unable to determine its position meeting operator + * policy within the GeoFencing Maximum Wait Time, it shall present the alert to the user and + * discontinue further positioning determination for the alert. + */ + private final int mMaximumWaitTimeSec; + /** UNIX timestamp of when the message was received. */ private final long mReceivedTimeMillis; @@ -202,8 +216,8 @@ public final class SmsCbMessage implements Parcelable { @Nullable SmsCbCmasInfo cmasWarningInfo) { this(messageFormat, geographicalScope, serialNumber, location, serviceCategory, language, - body, priority, etwsWarningInfo, cmasWarningInfo, null /* geometries */, - System.currentTimeMillis()); + body, priority, etwsWarningInfo, cmasWarningInfo, 0 /* maximumWaitingTime */, + null /* geometries */, System.currentTimeMillis()); } /** @@ -213,7 +227,7 @@ public final class SmsCbMessage implements Parcelable { public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber, SmsCbLocation location, int serviceCategory, String language, String body, int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo, - List<Geometry> geometries, long receivedTimeMillis) { + int maximumWaitTimeSec, List<Geometry> geometries, long receivedTimeMillis) { mMessageFormat = messageFormat; mGeographicalScope = geographicalScope; mSerialNumber = serialNumber; @@ -226,6 +240,7 @@ public final class SmsCbMessage implements Parcelable { mCmasWarningInfo = cmasWarningInfo; mReceivedTimeMillis = receivedTimeMillis; mGeometries = geometries; + mMaximumWaitTimeSec = maximumWaitTimeSec; } /** @@ -262,6 +277,7 @@ public final class SmsCbMessage implements Parcelable { mReceivedTimeMillis = in.readLong(); String geoStr = in.readString(); mGeometries = geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null; + mMaximumWaitTimeSec = in.readInt(); } /** @@ -295,6 +311,7 @@ public final class SmsCbMessage implements Parcelable { dest.writeLong(mReceivedTimeMillis); dest.writeString( mGeometries != null ? CbGeoUtils.encodeGeometriesToString(mGeometries) : null); + dest.writeInt(mMaximumWaitTimeSec); } @NonNull @@ -389,6 +406,15 @@ public final class SmsCbMessage implements Parcelable { } /** + * Get the Geo-Fencing Maximum Wait Time. + * @return the time in second. + * @hide + */ + public int getMaximumWaitingTime() { + return mMaximumWaitTimeSec; + } + + /** * Get the time when this message was received. * @return the time in millisecond */ @@ -475,6 +501,7 @@ public final class SmsCbMessage implements Parcelable { + ", priority=" + mPriority + (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "") + (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "") + + ", maximumWaitingTime = " + mMaximumWaitTimeSec + ", geo=" + (mGeometries != null ? CbGeoUtils.encodeGeometriesToString(mGeometries) : "null") + '}'; @@ -535,6 +562,8 @@ public final class SmsCbMessage implements Parcelable { cv.put(CellBroadcasts.GEOMETRIES, (String) null); } + cv.put(CellBroadcasts.MAXIMUM_WAIT_TIME, mMaximumWaitTimeSec); + return cv; } @@ -644,17 +673,21 @@ public final class SmsCbMessage implements Parcelable { List<Geometry> geometries = geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null; - long receivedTimeSec = cursor.getLong( + long receivedTimeMillis = cursor.getLong( cursor.getColumnIndexOrThrow(CellBroadcasts.RECEIVED_TIME)); + int maximumWaitTimeSec = cursor.getInt( + cursor.getColumnIndexOrThrow(CellBroadcasts.MAXIMUM_WAIT_TIME)); + return new SmsCbMessage(format, geoScope, serialNum, location, category, - language, body, priority, etwsInfo, cmasInfo, geometries, receivedTimeSec); + language, body, priority, etwsInfo, cmasInfo, maximumWaitTimeSec, geometries, + receivedTimeMillis); } /** * @return {@code True} if this message needs geo-fencing check. */ public boolean needGeoFencingCheck() { - return mGeometries != null; + return mMaximumWaitTimeSec > 0 && mGeometries != null; } } diff --git a/telephony/java/com/android/internal/telephony/CbGeoUtils.java b/telephony/java/com/android/internal/telephony/CbGeoUtils.java index 73dd822903f5..0b73252a1e1b 100644 --- a/telephony/java/com/android/internal/telephony/CbGeoUtils.java +++ b/telephony/java/com/android/internal/telephony/CbGeoUtils.java @@ -299,7 +299,8 @@ public class CbGeoUtils { * @return the encoded string. */ @NonNull - public static String encodeGeometriesToString(@NonNull List<Geometry> geometries) { + public static String encodeGeometriesToString(List<Geometry> geometries) { + if (geometries == null || geometries.isEmpty()) return ""; return geometries.stream() .map(geometry -> encodeGeometryToString(geometry)) .filter(encodedStr -> !TextUtils.isEmpty(encodedStr)) diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java index dca4e6b13b90..6eea118787a7 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java @@ -104,7 +104,7 @@ public class GsmSmsCbMessage { header.getSerialNumber(), location, header.getServiceCategory(), null, getEtwsPrimaryMessage(context, header.getEtwsInfo().getWarningType()), SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, header.getEtwsInfo(), - header.getCmasInfo(), null /* geometries */, receivedTimeMillis); + header.getCmasInfo(), 0, null /* geometries */, receivedTimeMillis); } else if (header.isUmtsFormat()) { // UMTS format has only 1 PDU byte[] pdu = pdus[0]; @@ -120,9 +120,13 @@ public class GsmSmsCbMessage { // Has Warning Area Coordinates information List<Geometry> geometries = null; + int maximumWaitingTimeSec = 255; if (pdu.length > wacDataOffset) { try { - geometries = parseWarningAreaCoordinates(pdu, wacDataOffset); + Pair<Integer, List<Geometry>> wac = parseWarningAreaCoordinates(pdu, + wacDataOffset); + maximumWaitingTimeSec = wac.first; + geometries = wac.second; } catch (Exception ex) { // Catch the exception here, the message will be considered as having no WAC // information which means the message will be broadcasted directly. @@ -133,7 +137,8 @@ public class GsmSmsCbMessage { return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP, header.getGeographicalScope(), header.getSerialNumber(), location, header.getServiceCategory(), language, body, priority, - header.getEtwsInfo(), header.getCmasInfo(), geometries, receivedTimeMillis); + header.getEtwsInfo(), header.getCmasInfo(), maximumWaitingTimeSec, geometries, + receivedTimeMillis); } else { String language = null; StringBuilder sb = new StringBuilder(); @@ -148,7 +153,7 @@ public class GsmSmsCbMessage { return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP, header.getGeographicalScope(), header.getSerialNumber(), location, header.getServiceCategory(), language, sb.toString(), priority, - header.getEtwsInfo(), header.getCmasInfo(), null /* geometries */, + header.getEtwsInfo(), header.getCmasInfo(), 0, null /* geometries */, receivedTimeMillis); } } @@ -197,7 +202,17 @@ public class GsmSmsCbMessage { } } - private static List<Geometry> parseWarningAreaCoordinates(byte[] pdu, int wacOffset) { + /** + * Parse the broadcast area and maximum wait time from the Warning Area Coordinates TLV. + * + * @param pdu Warning Area Coordinates TLV. + * @param wacOffset the offset of Warning Area Coordinates TLV. + * @return a pair with the first element is maximum wait time and the second is the broadcast + * area. The default value of the maximum wait time is 255 which means use the device default + * value. + */ + private static Pair<Integer, List<Geometry>> parseWarningAreaCoordinates( + byte[] pdu, int wacOffset) { // little-endian int wacDataLength = (pdu[wacOffset + 1] << 8) | pdu[wacOffset]; int offset = wacOffset + 2; @@ -209,6 +224,8 @@ public class GsmSmsCbMessage { BitStreamReader bitReader = new BitStreamReader(pdu, offset); + int maximumWaitTimeSec = SmsCbMessage.MAXIMUM_WAIT_TIME_NOT_SET; + List<Geometry> geo = new ArrayList<>(); int remainedBytes = wacDataLength; while (remainedBytes > 0) { @@ -220,8 +237,7 @@ public class GsmSmsCbMessage { switch (type) { case CbGeoUtils.GEO_FENCING_MAXIMUM_WAIT_TIME: - // TODO: handle the maximum wait time in cell broadcast provider. - int maximumWaitTimeSec = bitReader.read(8); + maximumWaitTimeSec = bitReader.read(8); break; case CbGeoUtils.GEOMETRY_TYPE_POLYGON: List<LatLng> latLngs = new ArrayList<>(); @@ -247,7 +263,7 @@ public class GsmSmsCbMessage { throw new IllegalArgumentException("Unsupported geoType = " + type); } } - return geo; + return new Pair(maximumWaitTimeSec, geo); } /** diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java index b2e5a62849e7..bc98f06ebc56 100644 --- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java +++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java @@ -28,6 +28,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.concurrent.TimeUnit; + /** * Runs the staged rollback tests. */ @@ -99,9 +101,15 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { // crash system_server enough times to trigger a rollback crashProcess("system_server", NATIVE_CRASHES_THRESHOLD); - // Rollback should be committed automatically now - // Give time for rollback to be committed - assertTrue(getDevice().waitForDeviceNotAvailable(60000)); + // Rollback should be committed automatically now. + // Give time for rollback to be committed. This could take a while, + // because we need all of the following to happen: + // 1. system_server comes back up and boot completes. + // 2. Rollback health observer detects updatable crashing signal. + // 3. Staged rollback session becomes ready. + // 4. Device actually reboots. + // So we give a generous timeout here. + assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5))); getDevice().waitForDeviceAvailable(); // verify rollback committed |