1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.deviceinfo.storage;
18
19import static com.android.settings.utils.FileSizeFormatter.MEGABYTE_IN_BYTES;
20import static com.google.common.truth.Truth.assertThat;
21import static org.mockito.Matchers.anyString;
22import static org.mockito.Mockito.mock;
23import static org.mockito.Mockito.verify;
24import static org.mockito.Mockito.when;
25
26import android.content.Context;
27import android.content.pm.UserInfo;
28import android.graphics.drawable.Drawable;
29import android.os.UserManager;
30import android.support.v7.preference.Preference;
31import android.support.v7.preference.PreferenceGroup;
32import android.support.v7.preference.PreferenceScreen;
33import android.util.SparseArray;
34
35import com.android.settings.testutils.SettingsRobolectricTestRunner;
36import com.android.settingslib.applications.StorageStatsSource;
37import com.android.settingslib.core.AbstractPreferenceController;
38import com.android.settingslib.drawable.UserIconDrawable;
39
40import org.junit.Before;
41import org.junit.Test;
42import org.junit.runner.RunWith;
43import org.mockito.ArgumentCaptor;
44import org.mockito.Mock;
45import org.mockito.MockitoAnnotations;
46import org.robolectric.RuntimeEnvironment;
47
48import java.util.ArrayList;
49import java.util.List;
50
51@RunWith(SettingsRobolectricTestRunner.class)
52public class SecondaryUserControllerTest {
53
54    private static final String TEST_NAME = "Fred";
55    private static final String TARGET_PREFERENCE_GROUP_KEY = "pref_secondary_users";
56    @Mock
57    private UserManager mUserManager;
58    @Mock
59    private PreferenceScreen mScreen;
60    @Mock
61    private PreferenceGroup mGroup;
62
63    private Context mContext;
64    private SecondaryUserController mController;
65    private UserInfo mPrimaryUser;
66
67    @Before
68    public void setUp() throws Exception {
69        MockitoAnnotations.initMocks(this);
70        mContext = RuntimeEnvironment.application;
71        mPrimaryUser = new UserInfo();
72        mPrimaryUser.flags = UserInfo.FLAG_PRIMARY;
73        mController = new SecondaryUserController(mContext, mPrimaryUser);
74
75        when(mScreen.getContext()).thenReturn(mContext);
76        when(mScreen.findPreference(anyString())).thenReturn(mGroup);
77        when(mGroup.getKey()).thenReturn(TARGET_PREFERENCE_GROUP_KEY);
78    }
79
80    @Test
81    public void controllerAddsSecondaryUser() {
82        mPrimaryUser.name = TEST_NAME;
83        mController.displayPreference(mScreen);
84
85        final ArgumentCaptor<Preference> argumentCaptor = ArgumentCaptor.forClass(Preference.class);
86        verify(mGroup).addPreference(argumentCaptor.capture());
87        final Preference preference = argumentCaptor.getValue();
88        assertThat(preference.getTitle()).isEqualTo(TEST_NAME);
89    }
90
91    @Test
92    public void controllerUpdatesSummaryOfNewPreference() {
93        mPrimaryUser.name = TEST_NAME;
94        mController.displayPreference(mScreen);
95        mController.setSize(MEGABYTE_IN_BYTES * 10);
96        final ArgumentCaptor<Preference> argumentCaptor = ArgumentCaptor.forClass(Preference.class);
97
98        verify(mGroup).addPreference(argumentCaptor.capture());
99
100        final Preference preference = argumentCaptor.getValue();
101        assertThat(preference.getSummary()).isEqualTo("0.01 GB");
102    }
103
104    @Test
105    public void noSecondaryUserAddedIfNoneExist() {
106        final ArrayList<UserInfo> userInfos = new ArrayList<>();
107        userInfos.add(mPrimaryUser);
108        when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser);
109        when(mUserManager.getUsers()).thenReturn(userInfos);
110        final List<AbstractPreferenceController> controllers =
111                SecondaryUserController.getSecondaryUserControllers(mContext, mUserManager);
112
113        assertThat(controllers).hasSize(1);
114        // We should have the NoSecondaryUserController.
115        assertThat(controllers.get(0) instanceof SecondaryUserController).isFalse();
116    }
117
118    @Test
119    public void secondaryUserAddedIfHasDistinctId() {
120        final ArrayList<UserInfo> userInfos = new ArrayList<>();
121        final UserInfo secondaryUser = new UserInfo();
122        secondaryUser.id = 10;
123        secondaryUser.profileGroupId = 101010; // this just has to be something not 0
124        userInfos.add(mPrimaryUser);
125        userInfos.add(secondaryUser);
126        when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser);
127        when(mUserManager.getUsers()).thenReturn(userInfos);
128        final List<AbstractPreferenceController> controllers =
129                SecondaryUserController.getSecondaryUserControllers(mContext, mUserManager);
130
131        assertThat(controllers).hasSize(1);
132        assertThat(controllers.get(0) instanceof SecondaryUserController).isTrue();
133    }
134
135    @Test
136    public void profilesOfPrimaryUserAreNotIgnored() {
137        final ArrayList<UserInfo> userInfos = new ArrayList<>();
138        final UserInfo secondaryUser = new UserInfo();
139        secondaryUser.id = mPrimaryUser.id;
140        userInfos.add(mPrimaryUser);
141        userInfos.add(secondaryUser);
142        when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser);
143        when(mUserManager.getUsers()).thenReturn(userInfos);
144
145        final List<AbstractPreferenceController> controllers =
146                SecondaryUserController.getSecondaryUserControllers(mContext, mUserManager);
147
148        assertThat(controllers).hasSize(2);
149        assertThat(controllers.get(0) instanceof UserProfileController).isTrue();
150        assertThat(controllers.get(1) instanceof SecondaryUserController).isFalse();
151    }
152
153    @Test
154    public void controllerUpdatesPreferenceOnAcceptingResult() {
155        mPrimaryUser.name = TEST_NAME;
156        mPrimaryUser.id = 10;
157        mController.displayPreference(mScreen);
158        final StorageAsyncLoader.AppsStorageResult userResult =
159                new StorageAsyncLoader.AppsStorageResult();
160        final SparseArray<StorageAsyncLoader.AppsStorageResult> result = new SparseArray<>();
161        userResult.externalStats =
162                new StorageStatsSource.ExternalStorageStats(
163                        MEGABYTE_IN_BYTES * 30,
164                        MEGABYTE_IN_BYTES * 10,
165                        MEGABYTE_IN_BYTES * 10,
166                        MEGABYTE_IN_BYTES * 10, 0);
167        result.put(10, userResult);
168
169        mController.handleResult(result);
170        final ArgumentCaptor<Preference> argumentCaptor = ArgumentCaptor.forClass(Preference.class);
171        verify(mGroup).addPreference(argumentCaptor.capture());
172        final Preference preference = argumentCaptor.getValue();
173
174        assertThat(preference.getSummary()).isEqualTo("0.03 GB");
175    }
176
177    @Test
178    public void dontAddPrimaryProfileAsASecondaryProfile() {
179        final ArrayList<UserInfo> userInfos = new ArrayList<>();
180        // The primary UserInfo may be a different object with a different name... but represent the
181        // same user!
182        final UserInfo primaryUserRenamed = new UserInfo();
183        primaryUserRenamed.name = "Owner";
184        primaryUserRenamed.flags = UserInfo.FLAG_PRIMARY;
185        userInfos.add(primaryUserRenamed);
186        when(mUserManager.getPrimaryUser()).thenReturn(mPrimaryUser);
187        when(mUserManager.getUsers()).thenReturn(userInfos);
188        final List<AbstractPreferenceController> controllers =
189                SecondaryUserController.getSecondaryUserControllers(mContext, mUserManager);
190
191        assertThat(controllers).hasSize(1);
192        // We should have the NoSecondaryUserController.
193        assertThat(controllers.get(0) instanceof SecondaryUserController).isFalse();
194    }
195
196    @Test
197    public void iconCallbackChangesPreferenceIcon() {
198        final SparseArray<Drawable> icons = new SparseArray<>();
199        final UserIconDrawable drawable = mock(UserIconDrawable.class);
200        when(drawable.mutate()).thenReturn(drawable);
201        mPrimaryUser.name = TEST_NAME;
202        mPrimaryUser.id = 10;
203        icons.put(mPrimaryUser.id, drawable);
204        mController.displayPreference(mScreen);
205
206        mController.handleUserIcons(icons);
207
208        final ArgumentCaptor<Preference> argumentCaptor = ArgumentCaptor.forClass(Preference.class);
209        verify(mGroup).addPreference(argumentCaptor.capture());
210        final Preference preference = argumentCaptor.getValue();
211        assertThat(preference.getIcon()).isEqualTo(drawable);
212    }
213
214    @Test
215    public void setIcon_doesntNpeOnNullPreference() {
216        final SparseArray<Drawable> icons = new SparseArray<>();
217        final UserIconDrawable drawable = mock(UserIconDrawable.class);
218        mPrimaryUser.name = TEST_NAME;
219        mPrimaryUser.id = 10;
220        icons.put(mPrimaryUser.id, drawable);
221
222        mController.handleUserIcons(icons);
223
224        // Doesn't crash
225    }
226}
227