Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7c67687 authored by Robert Snoeberger's avatar Robert Snoeberger Committed by android-build-merger
Browse files

Merge "Add tests for user changes." into qt-dev

am: 234ca31b

Change-Id: Ide76cb039192bdd6221450f6d7407402d0f18955
parents 2e9bc8bf 234ca31b
Loading
Loading
Loading
Loading
+20 −15
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.util.DisplayMetrics;
import android.view.LayoutInflater;

import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Observer;

import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -37,13 +38,14 @@ import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManager.DockEventListener;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.settings.CurrentUserObservable;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.util.InjectionInflationController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;

import javax.inject.Inject;
@@ -64,7 +66,7 @@ public final class ClockManager {
    private final ContentResolver mContentResolver;
    private final SettingsWrapper mSettingsWrapper;
    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
    private final CurrentUserTracker mCurrentUserTracker;
    private final CurrentUserObservable mCurrentUserObservable;

    /**
     * Observe settings changes to know when to switch the clock face.
@@ -74,12 +76,18 @@ public final class ClockManager {
                @Override
                public void onChange(boolean selfChange, Uri uri, int userId) {
                    super.onChange(selfChange, uri, userId);
                    if (userId == mCurrentUserTracker.getCurrentUserId()) {
                    if (Objects.equals(userId,
                            mCurrentUserObservable.getCurrentUser().getValue())) {
                        reload();
                    }
                }
            };

    /**
     * Observe user changes and react by potentially loading the custom clock for the new user.
     */
    private final Observer<Integer> mCurrentUserObserver = (newUserId) -> reload();

    private final PluginManager mPluginManager;

    /**
@@ -119,22 +127,19 @@ public final class ClockManager {
    public ClockManager(Context context, InjectionInflationController injectionInflater,
            PluginManager pluginManager, SysuiColorExtractor colorExtractor) {
        this(context, injectionInflater, pluginManager, colorExtractor,
                context.getContentResolver(), new SettingsWrapper(context.getContentResolver()));
                context.getContentResolver(), new CurrentUserObservable(context),
                new SettingsWrapper(context.getContentResolver()));
    }

    ClockManager(Context context, InjectionInflationController injectionInflater,
            PluginManager pluginManager, SysuiColorExtractor colorExtractor,
            ContentResolver contentResolver, SettingsWrapper settingsWrapper) {
            ContentResolver contentResolver, CurrentUserObservable currentUserObservable,
            SettingsWrapper settingsWrapper) {
        mContext = context;
        mPluginManager = pluginManager;
        mContentResolver = contentResolver;
        mSettingsWrapper = settingsWrapper;
        mCurrentUserTracker = new CurrentUserTracker(context) {
            @Override
            public void onUserSwitched(int newUserId) {
                reload();
            }
        };
        mCurrentUserObservable = currentUserObservable;
        mPreviewClocks = new AvailableClocks();

        Resources res = context.getResources();
@@ -217,7 +222,7 @@ public final class ClockManager {
        mContentResolver.registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.DOCKED_CLOCK_FACE),
                false, mContentObserver, UserHandle.USER_ALL);
        mCurrentUserTracker.startTracking();
        mCurrentUserObservable.getCurrentUser().observeForever(mCurrentUserObserver);
        if (mDockManager == null) {
            mDockManager = SysUiServiceProvider.getComponent(mContext, DockManager.class);
        }
@@ -229,7 +234,7 @@ public final class ClockManager {
    private void unregister() {
        mPluginManager.removePluginListener(mPreviewClocks);
        mContentResolver.unregisterContentObserver(mContentObserver);
        mCurrentUserTracker.stopTracking();
        mCurrentUserObservable.getCurrentUser().removeObserver(mCurrentUserObserver);
        if (mDockManager != null) {
            mDockManager.removeListener(mDockEventListener);
        }
@@ -347,7 +352,7 @@ public final class ClockManager {
            ClockPlugin plugin = null;
            if (ClockManager.this.isDocked()) {
                final String name = mSettingsWrapper.getDockedClockFace(
                        mCurrentUserTracker.getCurrentUserId());
                        mCurrentUserObservable.getCurrentUser().getValue());
                if (name != null) {
                    plugin = mClocks.get(name);
                    if (plugin != null) {
@@ -356,7 +361,7 @@ public final class ClockManager {
                }
            }
            final String name = mSettingsWrapper.getLockScreenCustomClockFace(
                    mCurrentUserTracker.getCurrentUserId());
                    mCurrentUserObservable.getCurrentUser().getValue());
            if (name != null) {
                plugin = mClocks.get(name);
            }
+63 −0
Original line number Diff line number Diff line
/*
 * 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.settings;

import android.content.Context;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

/**
 * A class that has an observable for the current user.
 */
public class CurrentUserObservable {

    private final CurrentUserTracker mTracker;

    private final MutableLiveData<Integer> mCurrentUser = new MutableLiveData<Integer>() {
        @Override
        protected void onActive() {
            super.onActive();
            mTracker.startTracking();
        }

        @Override
        protected void onInactive() {
            super.onInactive();
            mTracker.startTracking();
        }
    };

    public CurrentUserObservable(Context context) {
        mTracker = new CurrentUserTracker(context) {
            @Override
            public void onUserSwitched(int newUserId) {
                mCurrentUser.setValue(newUserId);
            }
        };
    }

    /**
     * Returns the current user that can be observed.
     */
    public LiveData<Integer> getCurrentUser() {
        if (mCurrentUser.getValue() == null) {
            mCurrentUser.setValue(mTracker.getCurrentUserId());
        }
        return mCurrentUser;
    }
}
+51 −8
Original line number Diff line number Diff line
@@ -31,11 +31,14 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;

import androidx.lifecycle.MutableLiveData;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerFake;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.settings.CurrentUserObservable;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.util.InjectionInflationController;

@@ -49,21 +52,26 @@ import org.mockito.MockitoAnnotations;

@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
// Need to run tests on main looper because LiveData operations such as setData, observe,
// removeObserver cannot be invoked on a background thread.
@RunWithLooper(setAsMainLooper = true)
public final class ClockManagerTest extends SysuiTestCase {

    private static final String BUBBLE_CLOCK = BubbleClockController.class.getName();
    private static final Class<?> BUBBLE_CLOCK_CLASS = BubbleClockController.class;
    private static final int USER_ID = 0;
    private static final int MAIN_USER_ID = 0;
    private static final int SECONDARY_USER_ID = 11;
    private static final Uri SETTINGS_URI = null;

    private ClockManager mClockManager;
    private ContentObserver mContentObserver;
    private DockManagerFake mFakeDockManager;
    private MutableLiveData<Integer> mCurrentUser;
    @Mock InjectionInflationController mMockInjectionInflationController;
    @Mock PluginManager mMockPluginManager;
    @Mock SysuiColorExtractor mMockColorExtractor;
    @Mock ContentResolver mMockContentResolver;
    @Mock CurrentUserObservable mMockCurrentUserObserable;
    @Mock SettingsWrapper mMockSettingsWrapper;
    @Mock ClockManager.ClockChangedListener mMockListener1;
    @Mock ClockManager.ClockChangedListener mMockListener2;
@@ -78,9 +86,13 @@ public final class ClockManagerTest extends SysuiTestCase {
        mFakeDockManager = new DockManagerFake();
        getContext().putComponent(DockManager.class, mFakeDockManager);

        mCurrentUser = new MutableLiveData<>();
        mCurrentUser.setValue(MAIN_USER_ID);
        when(mMockCurrentUserObserable.getCurrentUser()).thenReturn(mCurrentUser);

        mClockManager = new ClockManager(getContext(), mMockInjectionInflationController,
                mMockPluginManager, mMockColorExtractor, mMockContentResolver,
                mMockSettingsWrapper);
                mMockCurrentUserObserable, mMockSettingsWrapper);

        mClockManager.addOnClockChangedListener(mMockListener1);
        mClockManager.addOnClockChangedListener(mMockListener2);
@@ -113,7 +125,7 @@ public final class ClockManagerTest extends SysuiTestCase {
        when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(null);
        when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn(null);
        // WHEN settings change event is fired
        mContentObserver.onChange(false, SETTINGS_URI, USER_ID);
        mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
        // THEN the result is null, indicated the default clock face should be used.
        assertThat(mClockManager.getCurrentClock()).isNull();
    }
@@ -123,7 +135,7 @@ public final class ClockManagerTest extends SysuiTestCase {
        // GIVEN that settings is set to the bubble clock face
        when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
        // WHEN settings change event is fired
        mContentObserver.onChange(false, SETTINGS_URI, USER_ID);
        mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
        // THEN the plugin is the bubble clock face.
        assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
    }
@@ -133,7 +145,7 @@ public final class ClockManagerTest extends SysuiTestCase {
        // GIVEN that settings is set to the bubble clock face
        when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
        // WHEN settings change event is fired
        mContentObserver.onChange(false, SETTINGS_URI, USER_ID);
        mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
        // THEN the plugin is the bubble clock face.
        ArgumentCaptor<ClockPlugin> captor = ArgumentCaptor.forClass(ClockPlugin.class);
        verify(mMockListener1).onClockChanged(captor.capture());
@@ -145,7 +157,7 @@ public final class ClockManagerTest extends SysuiTestCase {
        // GIVEN that settings is set to the bubble clock face
        when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
        // WHEN settings change event is fired
        mContentObserver.onChange(false, SETTINGS_URI, USER_ID);
        mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
        // THEN the listeners receive separate instances of the Bubble clock plugin.
        ArgumentCaptor<ClockPlugin> captor1 = ArgumentCaptor.forClass(ClockPlugin.class);
        ArgumentCaptor<ClockPlugin> captor2 = ArgumentCaptor.forClass(ClockPlugin.class);
@@ -162,7 +174,7 @@ public final class ClockManagerTest extends SysuiTestCase {
        // custom clock face.
        when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn("bad value");
        // WHEN settings change event is fired
        mContentObserver.onChange(false, SETTINGS_URI, USER_ID);
        mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
        // THEN the result is null.
        assertThat(mClockManager.getCurrentClock()).isNull();
    }
@@ -206,4 +218,35 @@ public final class ClockManagerTest extends SysuiTestCase {
        // THEN the plugin is the bubble clock face.
        assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
    }

    @Test
    public void onUserChanged_defaultClock() {
        // WHEN the user changes
        mCurrentUser.setValue(SECONDARY_USER_ID);
        // THEN the plugin is null for the default clock face
        assertThat(mClockManager.getCurrentClock()).isNull();
    }

    @Test
    public void onUserChanged_customClock() {
        // GIVEN that a second user has selected the bubble clock face
        when(mMockSettingsWrapper.getLockScreenCustomClockFace(SECONDARY_USER_ID)).thenReturn(
                BUBBLE_CLOCK);
        // WHEN the user changes
        mCurrentUser.setValue(SECONDARY_USER_ID);
        // THEN the plugin is the bubble clock face.
        assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
    }

    @Test
    public void onUserChanged_docked() {
        // GIVEN device is docked
        mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
        // AND the second user as selected the bubble clock for the dock
        when(mMockSettingsWrapper.getDockedClockFace(SECONDARY_USER_ID)).thenReturn(BUBBLE_CLOCK);
        // WHEN the user changes
        mCurrentUser.setValue(SECONDARY_USER_ID);
        // THEN the plugin is the bubble clock face.
        assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
    }
}