diff options
author | Jovana Knezevic <jovanak@google.com> | 2018-06-25 22:14:32 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-06-25 22:14:32 +0000 |
commit | 4aff01310e105f5a26a418e1a1cd8596ca262b69 (patch) | |
tree | f2245b8db881ca0c74b31bfea0463474dc0d2ed5 | |
parent | d50321314e309f0062850733a6e7b5f582af5f8c (diff) | |
parent | 32c0c703325c07bca115bfd17a5620989f03e6d0 (diff) | |
download | Car-4aff01310e105f5a26a418e1a1cd8596ca262b69.tar.gz |
Merge "Enables registering/unregistering multiple update listeners." into pi-dev
-rw-r--r-- | car-lib/src/android/car/user/CarUserManagerHelper.java | 49 | ||||
-rw-r--r-- | tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java | 109 |
2 files changed, 142 insertions, 16 deletions
diff --git a/car-lib/src/android/car/user/CarUserManagerHelper.java b/car-lib/src/android/car/user/CarUserManagerHelper.java index db28d21cba..c5885477ab 100644 --- a/car-lib/src/android/car/user/CarUserManagerHelper.java +++ b/car-lib/src/android/car/user/CarUserManagerHelper.java @@ -38,6 +38,7 @@ import com.android.internal.util.UserIcons; import com.google.android.collect.Sets; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -67,15 +68,23 @@ public class CarUserManagerHelper { private final ActivityManager mActivityManager; private int mLastActiveUser = UserHandle.USER_SYSTEM; private Bitmap mDefaultGuestUserIcon; - private OnUsersUpdateListener mUpdateListener; + private ArrayList<OnUsersUpdateListener> mUpdateListeners; private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - mUpdateListener.onUsersUpdate(); + ArrayList<OnUsersUpdateListener> copyOfUpdateListeners; + synchronized (mUpdateListeners) { + copyOfUpdateListeners = new ArrayList(mUpdateListeners); + } + + for (OnUsersUpdateListener listener : copyOfUpdateListeners) { + listener.onUsersUpdate(); + } } }; public CarUserManagerHelper(Context context) { + mUpdateListeners = new ArrayList<>(); mContext = context.getApplicationContext(); mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); @@ -84,24 +93,42 @@ public class CarUserManagerHelper { /** * Registers a listener for updates to all users - removing, adding users or changing user info. * - * <p> Best practise is to keep one listener per helper. - * * @param listener Instance of {@link OnUsersUpdateListener}. */ public void registerOnUsersUpdateListener(OnUsersUpdateListener listener) { - if (mUpdateListener != null) { - unregisterOnUsersUpdateListener(); + if (listener == null) { + return; } - mUpdateListener = listener; - registerReceiver(); + synchronized (mUpdateListeners) { + if (mUpdateListeners.isEmpty()) { + // First listener being added, register receiver. + registerReceiver(); + } + + if (!mUpdateListeners.contains(listener)) { + mUpdateListeners.add(listener); + } + } } /** - * Unregisters on user update listener by unregistering {@code BroadcastReceiver}. + * Unregisters on user update listener. + * Unregisters {@code BroadcastReceiver} if no listeners remain. + * + * @param listener Instance of {@link OnUsersUpdateListener} to unregister. */ - public void unregisterOnUsersUpdateListener() { - unregisterReceiver(); + public void unregisterOnUsersUpdateListener(OnUsersUpdateListener listener) { + synchronized (mUpdateListeners) { + if (mUpdateListeners.contains(listener)) { + mUpdateListeners.remove(listener); + + if (mUpdateListeners.isEmpty()) { + // No more listeners, unregister broadcast receiver. + unregisterReceiver(); + } + } + } } /** diff --git a/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java b/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java index 240ba87cc0..8fc1eead69 100644 --- a/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java +++ b/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java @@ -19,8 +19,10 @@ package com.android.car; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.ActivityManager; @@ -40,17 +42,18 @@ import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** * This class contains unit tests for the {@link CarUserManagerHelper}. * It tests that {@link CarUserManagerHelper} does the right thing for user management flows. @@ -519,11 +522,107 @@ public class CarUserManagerHelperTest { assertThat(handlerCaptor.getValue()).isNull(); // Unregister the receiver. - mCarUserManagerHelper.unregisterOnUsersUpdateListener(); + mCarUserManagerHelper.unregisterOnUsersUpdateListener(mTestListener); verify(mContext).unregisterReceiver(receiverCaptor.getValue()); } @Test + public void testMultipleRegistrationsOfSameListener() { + CarUserManagerHelper.OnUsersUpdateListener listener = + Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class); + + ArgumentCaptor<BroadcastReceiver> receiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + + mCarUserManagerHelper.registerOnUsersUpdateListener(listener); + mCarUserManagerHelper.registerOnUsersUpdateListener(listener); + // Even for multiple registrations of the same listener, broadcast receiver registered once. + verify(mContext, times(1)) + .registerReceiverAsUser(receiverCaptor.capture(), any(), any(), any(), any()); + + // Verify that calling the receiver calls the listener. + receiverCaptor.getValue().onReceive(mContext, new Intent()); + verify(listener).onUsersUpdate(); + + // Verify that a single removal unregisters the listener. + mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener); + verify(mContext).unregisterReceiver(any()); + } + + @Test + public void testMultipleUnregistrationsOfTheSameListener() { + CarUserManagerHelper.OnUsersUpdateListener listener = + Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class); + mCarUserManagerHelper.registerOnUsersUpdateListener(listener); + + // Verify that a multiple unregistrations cause only one unregister for broadcast receiver. + mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener); + mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener); + mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener); + verify(mContext, times(1)).unregisterReceiver(any()); + } + + @Test + public void testUnregisterReceiverCalledAfterAllListenersUnregister() { + CarUserManagerHelper.OnUsersUpdateListener listener1 = + Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class); + CarUserManagerHelper.OnUsersUpdateListener listener2 = + Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class); + + mCarUserManagerHelper.registerOnUsersUpdateListener(listener1); + mCarUserManagerHelper.registerOnUsersUpdateListener(listener2); + + mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener1); + verify(mContext, never()).unregisterReceiver(any()); + + mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener2); + verify(mContext, times(1)).unregisterReceiver(any()); + } + + @Test + public void testRegisteringMultipleListeners() { + CarUserManagerHelper.OnUsersUpdateListener listener1 = + Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class); + CarUserManagerHelper.OnUsersUpdateListener listener2 = + Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class); + ArgumentCaptor<BroadcastReceiver> receiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + + mCarUserManagerHelper.registerOnUsersUpdateListener(listener1); + mCarUserManagerHelper.registerOnUsersUpdateListener(listener2); + verify(mContext, times(1)) + .registerReceiverAsUser(receiverCaptor.capture(), any(), any(), any(), any()); + + // Verify that calling the receiver calls both listeners. + receiverCaptor.getValue().onReceive(mContext, new Intent()); + verify(listener1).onUsersUpdate(); + verify(listener2).onUsersUpdate(); + } + + @Test + public void testUnregisteringListenerStopsUpdatesForListener() { + CarUserManagerHelper.OnUsersUpdateListener listener1 = + Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class); + CarUserManagerHelper.OnUsersUpdateListener listener2 = + Mockito.mock(CarUserManagerHelper.OnUsersUpdateListener.class); + ArgumentCaptor<BroadcastReceiver> receiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + + mCarUserManagerHelper.registerOnUsersUpdateListener(listener1); + mCarUserManagerHelper.registerOnUsersUpdateListener(listener2); + verify(mContext, times(1)) + .registerReceiverAsUser(receiverCaptor.capture(), any(), any(), any(), any()); + + // Unregister listener2 + mCarUserManagerHelper.unregisterOnUsersUpdateListener(listener2); + + // Verify that calling the receiver calls only one listener. + receiverCaptor.getValue().onReceive(mContext, new Intent()); + verify(listener1).onUsersUpdate(); + verify(listener2, never()).onUsersUpdate(); + } + + @Test public void testGetInitialUserWithValidLastActiveUser() { SystemProperties.set("android.car.systemuser.headless", "true"); int lastActiveUserId = 12; |