summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Matías Hernández <matiashe@google.com> 2024-10-14 09:46:13 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-10-14 09:46:13 +0000
commitb8bd4a55cfbffd80972d0d8be94d82aa582bd445 (patch)
treea4f6659ba3223441c7904276486a553a2240edc9
parent249f87d7838cfb32d8abce8c6097e37b911de12a (diff)
parent1d5156d9cc4d8d64f331122ef2336752e263cce5 (diff)
Merge "Fix EventConditionProvider for secondary users (and HSUM)" into main
-rw-r--r--core/java/android/app/notification.aconfig10
-rw-r--r--services/core/java/com/android/server/notification/CalendarTracker.java6
-rw-r--r--services/core/java/com/android/server/notification/ConditionProviders.java11
-rw-r--r--services/core/java/com/android/server/notification/CountdownConditionProvider.java6
-rw-r--r--services/core/java/com/android/server/notification/CustomManualConditionProvider.java6
-rw-r--r--services/core/java/com/android/server/notification/EventConditionProvider.java66
-rw-r--r--services/core/java/com/android/server/notification/ScheduleConditionProvider.java6
-rw-r--r--services/core/java/com/android/server/notification/SystemConditionProviderService.java8
-rw-r--r--services/core/java/com/android/server/notification/ZenModeConditions.java10
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/EventConditionProviderTest.java82
10 files changed, 187 insertions, 24 deletions
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 8014537e8838..4ec869a143c3 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -48,6 +48,16 @@ flag {
}
flag {
+ name: "modes_hsum"
+ namespace: "systemui"
+ description: "Fixes for modes (and DND/Zen in general) with HSUM or secondary users"
+ bug: "366203070"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "api_tvextender"
is_exported: true
namespace: "systemui"
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index cfcf6ebf9540..f186f4273f61 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -32,6 +32,8 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.PrintWriter;
import java.util.Date;
import java.util.Objects;
@@ -296,4 +298,8 @@ public class CalendarTracker {
void onChanged();
}
+ @VisibleForTesting // (otherwise = NONE)
+ public int getUserId() {
+ return mUserContext.getUserId();
+ }
}
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 66e61c076030..0b40d64e3a09 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -169,16 +169,15 @@ public class ConditionProviders extends ManagedServices {
for (int i = 0; i < mSystemConditionProviders.size(); i++) {
mSystemConditionProviders.valueAt(i).onBootComplete();
}
- if (mCallback != null) {
- mCallback.onBootComplete();
- }
}
@Override
public void onUserSwitched(int user) {
super.onUserSwitched(user);
- if (mCallback != null) {
- mCallback.onUserSwitched();
+ if (android.app.Flags.modesHsum()) {
+ for (int i = 0; i < mSystemConditionProviders.size(); i++) {
+ mSystemConditionProviders.valueAt(i).onUserSwitched(UserHandle.of(user));
+ }
}
}
@@ -515,10 +514,8 @@ public class ConditionProviders extends ManagedServices {
}
public interface Callback {
- void onBootComplete();
void onServiceAdded(ComponentName component);
void onConditionChanged(Uri id, Condition condition);
- void onUserSwitched();
}
}
diff --git a/services/core/java/com/android/server/notification/CountdownConditionProvider.java b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
index c3ace15a8c0f..bb8ccd20f9ab 100644
--- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
+import android.os.UserHandle;
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.text.format.DateUtils;
@@ -65,6 +66,11 @@ public class CountdownConditionProvider extends SystemConditionProviderService {
}
@Override
+ public void onUserSwitched(UserHandle user) {
+ // Nothing to do because countdown conditions are not tied to any user data.
+ }
+
+ @Override
public void dump(PrintWriter pw, DumpFilter filter) {
pw.println(" CountdownConditionProvider:");
pw.print(" mConnected="); pw.println(mConnected);
diff --git a/services/core/java/com/android/server/notification/CustomManualConditionProvider.java b/services/core/java/com/android/server/notification/CustomManualConditionProvider.java
index 9531c5e58851..52dc116c699d 100644
--- a/services/core/java/com/android/server/notification/CustomManualConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CustomManualConditionProvider.java
@@ -17,6 +17,7 @@
package com.android.server.notification;
import android.net.Uri;
+import android.os.UserHandle;
import android.service.notification.ZenModeConfig;
import java.io.PrintWriter;
@@ -40,6 +41,11 @@ public class CustomManualConditionProvider extends SystemConditionProviderServic
}
@Override
+ public void onUserSwitched(UserHandle user) {
+ // Nothing to do because we won't ever call notifyConditions.
+ }
+
+ @Override
public void onConnected() {
// No need to keep subscriptions because we won't ever call notifyConditions
}
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
index 00dd547f6c4e..ecc4cf72a1c3 100644
--- a/services/core/java/com/android/server/notification/EventConditionProvider.java
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -23,6 +24,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
@@ -37,6 +39,7 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.notification.CalendarTracker.CheckEventResult;
import com.android.server.notification.NotificationManagerService.DumpFilter;
import com.android.server.pm.PackageManagerService;
@@ -59,12 +62,13 @@ public class EventConditionProvider extends SystemConditionProviderService {
private static final String EXTRA_TIME = "time";
private static final long CHANGE_DELAY = 2 * 1000; // coalesce chatty calendar changes
- private final Context mContext = this;
+ @VisibleForTesting Context mContext = this;
private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
private final SparseArray<CalendarTracker> mTrackers = new SparseArray<>();
private final Handler mWorker;
private final HandlerThread mThread;
+ @Nullable private UserHandle mCurrentUser;
private boolean mConnected;
private boolean mRegistered;
private boolean mBootComplete; // don't hammer the calendar provider until boot completes.
@@ -114,10 +118,28 @@ public class EventConditionProvider extends SystemConditionProviderService {
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- reloadTrackers();
+ if (android.app.Flags.modesHsum()) {
+ if (mCurrentUser != null) {
+ // Possibly the intent signals a profile added on a different user, but it
+ // doesn't matter (except for a bit of wasted work here). We will reload
+ // trackers for that user when we switch.
+ reloadTrackers(mCurrentUser);
+ }
+ } else {
+ reloadTrackers();
+ }
}
}, filter);
- reloadTrackers();
+ if (!android.app.Flags.modesHsum()) {
+ reloadTrackers();
+ }
+ }
+
+ @Override
+ public void onUserSwitched(UserHandle user) {
+ if (DEBUG) Slog.d(TAG, "onUserSwitched: " + user);
+ mCurrentUser = user;
+ reloadTrackers(user);
}
@Override
@@ -157,8 +179,41 @@ public class EventConditionProvider extends SystemConditionProviderService {
}
}
+ private void reloadTrackers(UserHandle user) {
+ if (DEBUG) Slog.d(TAG, "reloadTrackers user=" + user);
+ for (int i = 0; i < mTrackers.size(); i++) {
+ mTrackers.valueAt(i).setCallback(null);
+ }
+ mTrackers.clear();
+
+ // Ensure that user is the main user and not a profile.
+ UserManager userManager = UserManager.get(mContext);
+ UserHandle possibleParent = userManager.getProfileParent(user);
+ if (possibleParent != null) {
+ Slog.wtf(TAG, "reloadTrackers should not be called with profile " + user
+ + "; continuing with parent " + possibleParent);
+ user = possibleParent;
+ }
+
+ for (UserInfo profile : userManager.getProfiles(user.getIdentifier())) {
+ final Context profileContext = getContextForUser(mContext, profile.getUserHandle());
+ if (profileContext == null) {
+ Slog.w(TAG, "Unable to create context for profile " + profile.id + " of user "
+ + user.getIdentifier());
+ continue;
+ }
+ mTrackers.put(profile.id, new CalendarTracker(mContext, profileContext));
+ }
+ evaluateSubscriptions();
+ }
+
+ @Deprecated // Remove when inlining MODES_HSUM
private void reloadTrackers() {
if (DEBUG) Slog.d(TAG, "reloadTrackers");
+ if (android.app.Flags.modesHsum()) {
+ Slog.wtf(TAG, "Shouldn't call reloadTrackers() without user in MODES_HSUM",
+ new Exception());
+ }
for (int i = 0; i < mTrackers.size(); i++) {
mTrackers.valueAt(i).setCallback(null);
}
@@ -325,4 +380,9 @@ public class EventConditionProvider extends SystemConditionProviderService {
evaluateSubscriptionsW();
}
};
+
+ @VisibleForTesting // (otherwise = NONE)
+ public SparseArray<CalendarTracker> getTrackers() {
+ return mTrackers;
+ }
}
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index 6efe88f6a155..24b090c6ffab 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -25,6 +25,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Binder;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.ScheduleCalendar;
@@ -115,6 +116,11 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
}
@Override
+ public void onUserSwitched(UserHandle user) {
+ // Nothing to do because time-based schedules are not tied to any user data.
+ }
+
+ @Override
public void onDestroy() {
super.onDestroy();
if (DEBUG) Slog.d(TAG, "onDestroy");
diff --git a/services/core/java/com/android/server/notification/SystemConditionProviderService.java b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
index 97073b77f1f7..656f9dfd0917 100644
--- a/services/core/java/com/android/server/notification/SystemConditionProviderService.java
+++ b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
@@ -19,6 +19,7 @@ package com.android.server.notification;
import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
+import android.os.UserHandle;
import android.service.notification.ConditionProviderService;
import android.service.notification.IConditionProvider;
import android.util.TimeUtils;
@@ -30,9 +31,10 @@ import java.util.Date;
public abstract class SystemConditionProviderService extends ConditionProviderService {
- abstract public void dump(PrintWriter pw, DumpFilter filter);
- abstract public boolean isValidConditionId(Uri id);
- abstract public void onBootComplete();
+ public abstract void dump(PrintWriter pw, DumpFilter filter);
+ public abstract boolean isValidConditionId(Uri id);
+ public abstract void onBootComplete();
+ public abstract void onUserSwitched(UserHandle user);
final ComponentName getComponent() {
return new ComponentName("android", this.getClass().getName());
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 50bfbc3530a9..b1f010c38d4e 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -102,16 +102,6 @@ public class ZenModeConditions implements ConditionProviders.Callback {
}
@Override
- public void onBootComplete() {
- // noop
- }
-
- @Override
- public void onUserSwitched() {
- // noop
- }
-
- @Override
public void onServiceAdded(ComponentName component) {
if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
final int callingUid = Binder.getCallingUid();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/EventConditionProviderTest.java b/services/tests/uiservicestests/src/com/android/server/notification/EventConditionProviderTest.java
index 4af96ef4800f..05210aca19dd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/EventConditionProviderTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/EventConditionProviderTest.java
@@ -19,13 +19,25 @@ package com.android.server.notification;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import android.app.Application;
import android.app.PendingIntent;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
@@ -35,16 +47,24 @@ import com.android.server.UiServiceTestCase;
import com.android.server.pm.PackageManagerService;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+import java.util.List;
@RunWith(AndroidTestingRunner.class)
@SmallTest
@RunWithLooper
public class EventConditionProviderTest extends UiServiceTestCase {
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
- EventConditionProvider mService;
+ private EventConditionProvider mService;
+ @Mock private UserManager mUserManager;
@Before
public void setUp() throws Exception {
@@ -65,6 +85,18 @@ public class EventConditionProviderTest extends UiServiceTestCase {
service.onCreate();
service.onBind(startIntent);
mService = spy(service);
+ mService.mContext = this.getContext();
+
+ mContext.addMockSystemService(UserManager.class, mUserManager);
+ when(mUserManager.getProfiles(eq(mUserId))).thenReturn(
+ List.of(new UserInfo(mUserId, "mUserId", 0)));
+
+ doAnswer((Answer<Context>) invocationOnMock -> {
+ Context mockUserContext = mock(Context.class);
+ UserHandle userHandle = invocationOnMock.getArgument(2);
+ when(mockUserContext.getUserId()).thenReturn(userHandle.getIdentifier());
+ return mockUserContext;
+ }).when(mContext).createPackageContextAsUser(any(), anyInt(), any());
}
@Test
@@ -78,4 +110,52 @@ public class EventConditionProviderTest extends UiServiceTestCase {
PendingIntent pi = mService.getPendingIntent(1000);
assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME, pi.getIntent().getPackage());
}
+
+ @Test
+ @DisableFlags(android.app.Flags.FLAG_MODES_HSUM)
+ public void onBootComplete_flagOff_loadsTrackers() {
+ when(mUserManager.getUserProfiles()).thenReturn(List.of(UserHandle.of(mUserId)));
+
+ mService.onBootComplete();
+
+ assertThat(mService.getTrackers().size()).isEqualTo(1);
+ assertThat(mService.getTrackers().keyAt(0)).isEqualTo(mUserId);
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_HSUM)
+ public void onBootComplete_waitsForUserSwitched() {
+ mService.onBootComplete();
+ assertThat(mService.getTrackers().size()).isEqualTo(0);
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_HSUM)
+ public void onUserSwitched_reloadsTrackers() {
+ UserHandle someUser = UserHandle.of(42);
+ when(mUserManager.getProfiles(eq(42))).thenReturn(List.of(new UserInfo(42, "user 42", 0)));
+
+ mService.onUserSwitched(someUser);
+
+ assertThat(mService.getTrackers().size()).isEqualTo(1);
+ assertThat(mService.getTrackers().keyAt(0)).isEqualTo(42);
+ assertThat(mService.getTrackers().valueAt(0).getUserId()).isEqualTo(42);
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_HSUM)
+ public void onUserSwitched_reloadsTrackersIncludingProfiles() {
+ UserHandle anotherUser = UserHandle.of(42);
+ when(mUserManager.getProfiles(eq(42))).thenReturn(List.of(
+ new UserInfo(42, "user 42", 0),
+ new UserInfo(43, "profile 43", 0)));
+
+ mService.onUserSwitched(anotherUser);
+
+ assertThat(mService.getTrackers().size()).isEqualTo(2);
+ assertThat(mService.getTrackers().keyAt(0)).isEqualTo(42);
+ assertThat(mService.getTrackers().valueAt(0).getUserId()).isEqualTo(42);
+ assertThat(mService.getTrackers().keyAt(1)).isEqualTo(43);
+ assertThat(mService.getTrackers().valueAt(1).getUserId()).isEqualTo(43);
+ }
}