Merge "Replace observer for USER_SWITCHED broadbast by a UserSwitchObserver" into main
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index fab0430..99ce3e2 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -31,6 +31,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.SynchronousUserSwitchObserver;
 import android.app.UidObserver;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -145,8 +146,6 @@
                     PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE,
                     PowerManager.GO_TO_SLEEP_REASON_TIMEOUT));
 
-    private static final IntentFilter USER_SWITCHED_INTENT_FILTER =
-            new IntentFilter(Intent.ACTION_USER_SWITCHED);
     private static final IntentFilter INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER =
             new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
 
@@ -162,9 +161,11 @@
     @VisibleForTesting
     final SettingsContentObserver mSettingObserver;
     @VisibleForTesting
-    final MyUidObserver mUidObserver;
-    @VisibleForTesting
     final SettingsBroadcastReceiver mSettingChangeReceiver;
+    @VisibleForTesting
+    final VibrationUidObserver mUidObserver;
+    @VisibleForTesting
+    final VibrationUserSwitchObserver mUserSwitchObserver;
 
     @GuardedBy("mLock")
     private final List<OnVibratorSettingsChanged> mListeners = new ArrayList<>();
@@ -205,8 +206,9 @@
         mContext = context;
         mVibrationConfig = config;
         mSettingObserver = new SettingsContentObserver(handler);
-        mUidObserver = new MyUidObserver();
         mSettingChangeReceiver = new SettingsBroadcastReceiver();
+        mUidObserver = new VibrationUidObserver();
+        mUserSwitchObserver = new VibrationUserSwitchObserver();
         mSystemUiPackage = LocalServices.getService(PackageManagerInternal.class)
                 .getSystemUiServiceComponent().getPackageName();
 
@@ -245,7 +247,13 @@
         try {
             ActivityManager.getService().registerUidObserver(mUidObserver,
                     ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
-                    ActivityManager.PROCESS_STATE_UNKNOWN, null);
+                    ActivityManager.PROCESS_STATE_UNKNOWN, /* callingPackage= */ null);
+        } catch (RemoteException e) {
+            // ignored; both services live in system_server
+        }
+
+        try {
+            ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
         } catch (RemoteException e) {
             // ignored; both services live in system_server
         }
@@ -270,7 +278,6 @@
                     }
                 });
 
-        registerSettingsChangeReceiver(USER_SWITCHED_INTENT_FILTER);
         registerSettingsChangeReceiver(INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER);
 
         // Listen to all settings that might affect the result of Vibrator.getVibrationIntensity.
@@ -540,41 +547,44 @@
 
     /** Update all cached settings and triggers registered listeners. */
     void update() {
-        updateSettings();
+        updateSettings(UserHandle.USER_CURRENT);
         updateRingerMode();
         notifyListeners();
     }
 
-    private void updateSettings() {
+    private void updateSettings(int userHandle) {
         synchronized (mLock) {
-            mVibrateInputDevices = loadSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0;
-            mVibrateOn = loadSystemSetting(Settings.System.VIBRATE_ON, 1) > 0;
+            mVibrateInputDevices =
+                    loadSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0, userHandle) > 0;
+            mVibrateOn = loadSystemSetting(Settings.System.VIBRATE_ON, 1, userHandle) > 0;
             mKeyboardVibrationOn = loadSystemSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED,
-                    mVibrationConfig.isDefaultKeyboardVibrationEnabled() ? 1 : 0) > 0;
+                    mVibrationConfig.isDefaultKeyboardVibrationEnabled() ? 1 : 0, userHandle) > 0;
 
             int alarmIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.ALARM_VIBRATION_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.ALARM_VIBRATION_INTENSITY, -1, userHandle),
                     getDefaultIntensity(USAGE_ALARM));
             int defaultHapticFeedbackIntensity = getDefaultIntensity(USAGE_TOUCH);
             int hapticFeedbackIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, -1, userHandle),
                     defaultHapticFeedbackIntensity);
             int positiveHapticFeedbackIntensity = toPositiveIntensity(
                     hapticFeedbackIntensity, defaultHapticFeedbackIntensity);
             int hardwareFeedbackIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, -1,
+                            userHandle),
                     positiveHapticFeedbackIntensity);
             int mediaIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, -1, userHandle),
                     getDefaultIntensity(USAGE_MEDIA));
             int defaultNotificationIntensity = getDefaultIntensity(USAGE_NOTIFICATION);
             int notificationIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, -1,
+                            userHandle),
                     defaultNotificationIntensity);
             int positiveNotificationIntensity = toPositiveIntensity(
                     notificationIntensity, defaultNotificationIntensity);
             int ringIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.RING_VIBRATION_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.RING_VIBRATION_INTENSITY, -1, userHandle),
                     getDefaultIntensity(USAGE_RINGTONE));
 
             mCurrentVibrationIntensities.clear();
@@ -593,7 +603,7 @@
             mCurrentVibrationIntensities.put(USAGE_HARDWARE_FEEDBACK, hardwareFeedbackIntensity);
             mCurrentVibrationIntensities.put(USAGE_PHYSICAL_EMULATION, hardwareFeedbackIntensity);
 
-            if (!loadBooleanSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED)) {
+            if (!loadBooleanSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, userHandle)) {
                 // Make sure deprecated boolean setting still disables touch vibrations.
                 mCurrentVibrationIntensities.put(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_OFF);
             } else {
@@ -744,14 +754,13 @@
         return value;
     }
 
-    private boolean loadBooleanSetting(String settingKey) {
-        return Settings.System.getIntForUser(mContext.getContentResolver(),
-                settingKey, 0, UserHandle.USER_CURRENT) != 0;
+    private boolean loadBooleanSetting(String settingKey, int userHandle) {
+        return loadSystemSetting(settingKey, 0, userHandle) != 0;
     }
 
-    private int loadSystemSetting(String settingName, int defaultValue) {
+    private int loadSystemSetting(String settingName, int defaultValue, int userHandle) {
         return Settings.System.getIntForUser(mContext.getContentResolver(),
-                settingName, defaultValue, UserHandle.USER_CURRENT);
+                settingName, defaultValue, userHandle);
     }
 
     private void registerSettingsObserver(Uri settingUri) {
@@ -828,24 +837,18 @@
 
         @Override
         public void onChange(boolean selfChange) {
-            updateSettings();
+            updateSettings(UserHandle.USER_CURRENT);
             notifyListeners();
         }
     }
 
-    /**
-     * Implementation of {@link BroadcastReceiver} to update settings on current user or ringer
-     * mode change.
-     */
+    /** Implementation of {@link BroadcastReceiver} to update on ringer mode change. */
     @VisibleForTesting
     final class SettingsBroadcastReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                // Reload all settings, as they are user-based.
-                update();
-            } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
+            if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
                 updateRingerMode();
                 notifyListeners();
             }
@@ -854,7 +857,7 @@
 
     /** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */
     @VisibleForTesting
-    final class MyUidObserver extends UidObserver {
+    final class VibrationUidObserver extends UidObserver {
         private final SparseArray<Integer> mProcStatesCache = new SparseArray<>();
 
         public boolean isUidForeground(int uid) {
@@ -878,4 +881,23 @@
             }
         }
     }
+
+    /** Implementation of {@link SynchronousUserSwitchObserver} to update on user switch. */
+    @VisibleForTesting
+    final class VibrationUserSwitchObserver extends SynchronousUserSwitchObserver {
+
+        @Override
+        public void onUserSwitching(int newUserId) {
+            // Reload settings early based on new user id.
+            updateSettings(newUserId);
+            notifyListeners();
+        }
+
+        @Override
+        public void onUserSwitchComplete(int newUserId) {
+            // Reload all settings including ones from AudioManager,
+            // as they are based on UserHandle.USER_CURRENT.
+            update();
+        }
+    }
 }
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
index f080341..f54c7e5 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -100,6 +100,8 @@
     @Rule
     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
+    private static final int OLD_USER_ID = 123;
+    private static final int NEW_USER_ID = 456;
     private static final int UID = 1;
     private static final int VIRTUAL_DEVICE_ID = 1;
     private static final String SYSUI_PACKAGE_NAME = "sysui";
@@ -211,10 +213,10 @@
         mVibrationSettings.addListener(mListenerMock);
 
         // Testing the broadcast flow manually.
-        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
-                new Intent(Intent.ACTION_USER_SWITCHED));
+        mVibrationSettings.mUserSwitchObserver.onUserSwitching(NEW_USER_ID);
+        mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID);
 
-        verify(mListenerMock).onChange();
+        verify(mListenerMock, times(2)).onChange();
     }
 
     @Test
@@ -265,8 +267,7 @@
         // Trigger multiple observers manually.
         mVibrationSettings.mSettingObserver.onChange(false);
         mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
-        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
-                new Intent(Intent.ACTION_USER_SWITCHED));
+        mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID);
         mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
                 new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
 
@@ -834,13 +835,17 @@
         assertEquals(VIBRATION_INTENSITY_HIGH,
                 mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
 
-        // Switching user is not working with FakeSettingsProvider.
-        // Testing the broadcast flow manually.
-        Settings.System.putIntForUser(mContextSpy.getContentResolver(),
-                Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW,
+        // Test early update of settings based on new user id.
+        putUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW,
+                NEW_USER_ID);
+        mVibrationSettings.mUserSwitchObserver.onUserSwitching(NEW_USER_ID);
+        assertEquals(VIBRATION_INTENSITY_LOW,
+                mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
+
+        // Test later update of settings for UserHandle.USER_CURRENT.
+        putUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW,
                 UserHandle.USER_CURRENT);
-        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
-                new Intent(Intent.ACTION_USER_SWITCHED));
+        mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID);
         assertEquals(VIBRATION_INTENSITY_LOW,
                 mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
     }
@@ -956,12 +961,16 @@
     }
 
     private void setUserSetting(String settingName, int value) {
-        Settings.System.putIntForUser(
-                mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
+        putUserSetting(settingName, value, UserHandle.USER_CURRENT);
         // FakeSettingsProvider doesn't support testing triggering ContentObserver yet.
         mVibrationSettings.mSettingObserver.onChange(false);
     }
 
+    private void putUserSetting(String settingName, int value, int userHandle) {
+        Settings.System.putIntForUser(
+                mContextSpy.getContentResolver(), settingName, value, userHandle);
+    }
+
     private void setRingerMode(int ringerMode) {
         when(mAudioManagerMock.getRingerModeInternal()).thenReturn(ringerMode);
         // Mock AudioManager broadcast of internal ringer mode change.