• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 package com.android.documentsui.sidebar;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import android.app.admin.DevicePolicyManager;
22 import android.content.res.Resources;
23 import android.view.View;
24 
25 import androidx.test.filters.MediumTest;
26 import androidx.test.platform.app.InstrumentationRegistry;
27 import androidx.test.runner.AndroidJUnit4;
28 
29 import com.android.documentsui.R;
30 import com.android.documentsui.TestConfigStore;
31 import com.android.documentsui.base.State;
32 import com.android.documentsui.base.UserId;
33 import com.android.documentsui.testing.TestProvidersAccess;
34 import com.android.modules.utils.build.SdkLevel;
35 
36 import com.google.common.collect.Lists;
37 import com.google.common.truth.Correspondence;
38 
39 import org.junit.Before;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 
43 import java.util.ArrayList;
44 import java.util.Collections;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Objects;
49 
50 /**
51  * A unit test for {@link UserItemsCombiner}.
52  */
53 @RunWith(AndroidJUnit4.class)
54 @MediumTest
55 public class UserItemsCombinerTest {
56     private static final UserId PERSONAL_USER = TestProvidersAccess.USER_ID;
57     private static final UserId WORK_USER = TestProvidersAccess.OtherUser.USER_ID;
58     private static final UserId PRIVATE_USER = TestProvidersAccess.AnotherUser.USER_ID;
59 
60     private static final List<Item> PERSONAL_ITEMS = Lists.newArrayList(
61             personalItem("personal 1"),
62             personalItem("personal 2"),
63             personalItem("personal 3")
64     );
65 
66     private static final List<Item> WORK_ITEMS = Lists.newArrayList(
67             workItem("work 1")
68     );
69 
70     private static final List<Item> PRIVATE_ITEMS = Lists.newArrayList(
71             privateItem("private1")
72     );
73 
74     private static final Correspondence<Item, Item> ITEM_CORRESPONDENCE =
75             Correspondence.from((Item actual, Item expected) -> {
76                 return Objects.equals(actual.title, expected.title)
77                         && Objects.equals(actual.userId, expected.userId);
78             }, "has same title and userId as in");
79 
80     private final State mState = new State();
81     private final Resources mResources =
82             InstrumentationRegistry.getInstrumentation().getTargetContext().getResources();
83     private final DevicePolicyManager mDpm =
84             InstrumentationRegistry.getInstrumentation().getTargetContext().getSystemService(
85                     DevicePolicyManager.class);
86     private final List<UserId> mUserIds = new ArrayList<>();
87     private final Map<UserId, String> mUserIdToLabelMap = new HashMap<>();
88     private final TestConfigStore mTestConfigStore = new TestConfigStore();
89     private UserItemsCombiner mCombiner;
90 
91     @Before
setUp()92     public void setUp() {
93         mState.canShareAcrossProfile = true;
94         mState.supportsCrossProfile = true;
95         mUserIds.add(PERSONAL_USER);
96         mUserIds.add(WORK_USER);
97         mUserIdToLabelMap.put(PERSONAL_USER, "Personal");
98         mUserIdToLabelMap.put(WORK_USER, "Work");
99         mState.canForwardToProfileIdMap.put(PERSONAL_USER, true);
100         mState.canForwardToProfileIdMap.put(WORK_USER, true);
101         mState.configStore = mTestConfigStore;
102 
103         if (SdkLevel.isAtLeastV()) {
104             mUserIds.add(PRIVATE_USER);
105             mUserIdToLabelMap.put(PRIVATE_USER, "Private");
106             mState.canForwardToProfileIdMap.put(PRIVATE_USER, true);
107             mTestConfigStore.enablePrivateSpaceInPhotoPicker();
108         }
109     }
110 
111     @Test
testCreatePresentableList_empty()112     public void testCreatePresentableList_empty() {
113         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
114                 .setRootListForCurrentUser(Collections.emptyList())
115                 .setRootListForOtherUser(Collections.emptyList());
116         assertThat(mCombiner.createPresentableList()).isEmpty();
117     }
118 
119     @Test
testCreatePresentableListForAllUsers_empty()120     public void testCreatePresentableListForAllUsers_empty() {
121         final List<List<Item>> rootListAllUsers = new ArrayList<>();
122         rootListAllUsers.add(Collections.emptyList());
123         rootListAllUsers.add(Collections.emptyList());
124         if (SdkLevel.isAtLeastV()) {
125             rootListAllUsers.add(Collections.emptyList());
126         }
127         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
128                 .setRootListForAllUsers(rootListAllUsers);
129         assertThat(
130                 mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)).isEmpty();
131     }
132 
133     @Test
testCreatePresentableList_currentIsPersonal_personalItemsOnly()134     public void testCreatePresentableList_currentIsPersonal_personalItemsOnly() {
135         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
136                 .setRootListForCurrentUser(PERSONAL_ITEMS)
137                 .setRootListForOtherUser(Collections.emptyList());
138         assertThat(mCombiner.createPresentableList())
139                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
140                 .containsExactlyElementsIn(PERSONAL_ITEMS)
141                 .inOrder();
142     }
143 
144     @Test
testCreatePresentableList_currentIsWork_personalItemsOnly()145     public void testCreatePresentableList_currentIsWork_personalItemsOnly() {
146         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
147                 .overrideCurrentUserForTest(WORK_USER)
148                 .setRootListForCurrentUser(Collections.emptyList())
149                 .setRootListForOtherUser(PERSONAL_ITEMS);
150         assertThat(mCombiner.createPresentableList())
151                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
152                 .containsExactlyElementsIn(PERSONAL_ITEMS)
153                 .inOrder();
154     }
155 
156     @Test
testCreatePresentableListForAllUsers_currentIsPersonal_personalItemsOnly()157     public void testCreatePresentableListForAllUsers_currentIsPersonal_personalItemsOnly() {
158         final List<List<Item>> rootListAllUsers = new ArrayList<>();
159         rootListAllUsers.add(Lists.newArrayList(PERSONAL_ITEMS));
160         rootListAllUsers.add(Collections.emptyList());
161         if (SdkLevel.isAtLeastV()) {
162             rootListAllUsers.add(Collections.emptyList());
163         }
164         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
165                 .setRootListForAllUsers(rootListAllUsers);
166         assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap))
167                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
168                 .containsExactlyElementsIn(PERSONAL_ITEMS)
169                 .inOrder();
170     }
171 
172     @Test
testCreatePresentableListForAllUsers_currentIsWork_personalItemsOnly()173     public void testCreatePresentableListForAllUsers_currentIsWork_personalItemsOnly() {
174         final List<List<Item>> rootListAllUsers = new ArrayList<>();
175         rootListAllUsers.add(Lists.newArrayList(PERSONAL_ITEMS));
176         rootListAllUsers.add(Collections.emptyList());
177         if (SdkLevel.isAtLeastV()) {
178             rootListAllUsers.add(Collections.emptyList());
179         }
180         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
181                 .overrideCurrentUserForTest(WORK_USER)
182                 .setRootListForAllUsers(rootListAllUsers);
183         assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap))
184                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
185                 .containsExactlyElementsIn(PERSONAL_ITEMS)
186                 .inOrder();
187     }
188 
189     @Test
testCreatePresentableListForAllUsers_currentIsPrivate_personalItemsOnly()190     public void testCreatePresentableListForAllUsers_currentIsPrivate_personalItemsOnly() {
191         if (!SdkLevel.isAtLeastV()) return;
192         final List<List<Item>> rootListAllUsers = new ArrayList<>();
193         rootListAllUsers.add(Lists.newArrayList(PERSONAL_ITEMS));
194         rootListAllUsers.add(Collections.emptyList());
195         rootListAllUsers.add(Collections.emptyList());
196         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
197                 .overrideCurrentUserForTest(PRIVATE_USER)
198                 .setRootListForAllUsers(rootListAllUsers);
199         assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap))
200                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
201                 .containsExactlyElementsIn(PERSONAL_ITEMS)
202                 .inOrder();
203     }
204 
205     @Test
testCreatePresentableList_currentIsPersonal_workItemsOnly()206     public void testCreatePresentableList_currentIsPersonal_workItemsOnly() {
207         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
208                 .setRootListForCurrentUser(Collections.emptyList())
209                 .setRootListForOtherUser(WORK_ITEMS);
210         assertThat(mCombiner.createPresentableList())
211                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
212                 .containsExactlyElementsIn(WORK_ITEMS)
213                 .inOrder();
214     }
215 
216     @Test
testCreatePresentableList_currentIsWork_workItemsOnly()217     public void testCreatePresentableList_currentIsWork_workItemsOnly() {
218         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
219                 .overrideCurrentUserForTest(WORK_USER)
220                 .setRootListForCurrentUser(WORK_ITEMS)
221                 .setRootListForOtherUser(Collections.emptyList());
222         assertThat(mCombiner.createPresentableList())
223                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
224                 .containsExactlyElementsIn(WORK_ITEMS)
225                 .inOrder();
226     }
227 
228     @Test
testCreatePresentableListForAllUsers_currentIsPersonal_workItemsOnly()229     public void testCreatePresentableListForAllUsers_currentIsPersonal_workItemsOnly() {
230         final List<List<Item>> rootListAllUsers = new ArrayList<>();
231         rootListAllUsers.add(Collections.emptyList());
232         rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS));
233         if (SdkLevel.isAtLeastV()) {
234             rootListAllUsers.add(Collections.emptyList());
235         }
236         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
237                 .overrideCurrentUserForTest(PERSONAL_USER)
238                 .setRootListForAllUsers(rootListAllUsers);
239         assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap))
240                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
241                 .containsExactlyElementsIn(WORK_ITEMS)
242                 .inOrder();
243     }
244 
245     @Test
testCreatePresentableListForAllUsers_currentIsWork_workItemsOnly()246     public void testCreatePresentableListForAllUsers_currentIsWork_workItemsOnly() {
247         final List<List<Item>> rootListAllUsers = new ArrayList<>();
248         rootListAllUsers.add(Collections.emptyList());
249         rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS));
250         if (SdkLevel.isAtLeastV()) {
251             rootListAllUsers.add(Collections.emptyList());
252         }
253         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
254                 .overrideCurrentUserForTest(WORK_USER)
255                 .setRootListForAllUsers(rootListAllUsers);
256         assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap))
257                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
258                 .containsExactlyElementsIn(WORK_ITEMS)
259                 .inOrder();
260     }
261 
262     @Test
testCreatePresentableListForAllUsers_currentIsPrivate_workItemsOnly()263     public void testCreatePresentableListForAllUsers_currentIsPrivate_workItemsOnly() {
264         if (!SdkLevel.isAtLeastV()) return;
265         final List<List<Item>> rootListAllUsers = new ArrayList<>();
266         rootListAllUsers.add(Collections.emptyList());
267         rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS));
268         rootListAllUsers.add(Collections.emptyList());
269         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
270                 .overrideCurrentUserForTest(PRIVATE_USER)
271                 .setRootListForAllUsers(rootListAllUsers);
272         assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap))
273                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
274                 .containsExactlyElementsIn(WORK_ITEMS)
275                 .inOrder();
276     }
277 
278     @Test
testCreatePresentableList_currentIsPersonal_personalAndWorkItems()279     public void testCreatePresentableList_currentIsPersonal_personalAndWorkItems() {
280         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
281                 .setRootListForCurrentUser(PERSONAL_ITEMS)
282                 .setRootListForOtherUser(WORK_ITEMS);
283 
284         List<Item> expected = Lists.newArrayList();
285         expected.add(new HeaderItem(mResources.getString(R.string.personal_tab)));
286         expected.addAll(PERSONAL_ITEMS);
287         expected.add(new HeaderItem(mResources.getString(R.string.work_tab)));
288         expected.addAll(WORK_ITEMS);
289 
290         assertThat(mCombiner.createPresentableList())
291                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
292                 .containsExactlyElementsIn(expected)
293                 .inOrder();
294     }
295 
296     @Test
testCreatePresentableList_currentIsWork_personalAndWorkItems()297     public void testCreatePresentableList_currentIsWork_personalAndWorkItems() {
298         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
299                 .overrideCurrentUserForTest(WORK_USER)
300                 .setRootListForCurrentUser(WORK_ITEMS)
301                 .setRootListForOtherUser(PERSONAL_ITEMS);
302 
303         List<Item> expected = Lists.newArrayList();
304         expected.add(new HeaderItem(mResources.getString(R.string.personal_tab)));
305         expected.addAll(PERSONAL_ITEMS);
306         expected.add(new HeaderItem(mResources.getString(R.string.work_tab)));
307         expected.addAll(WORK_ITEMS);
308 
309         assertThat(mCombiner.createPresentableList())
310                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
311                 .containsExactlyElementsIn(expected)
312                 .inOrder();
313     }
314 
315     @Test
testCreatePresentableListForAllUsers_currentIsPersonal_allUsersItems()316     public void testCreatePresentableListForAllUsers_currentIsPersonal_allUsersItems() {
317         final List<List<Item>> rootListAllUsers = new ArrayList<>();
318         rootListAllUsers.add(PERSONAL_ITEMS);
319         rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS));
320         if (SdkLevel.isAtLeastV()) {
321             rootListAllUsers.add(PRIVATE_ITEMS);
322         }
323         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
324                 .setRootListForAllUsers(rootListAllUsers);
325 
326         List<Item> expected = Lists.newArrayList();
327         expected.add(new HeaderItem("Personal"));
328         expected.addAll(PERSONAL_ITEMS);
329         expected.add(new HeaderItem("Work"));
330         expected.addAll(WORK_ITEMS);
331         if (SdkLevel.isAtLeastV()) {
332             expected.add(new HeaderItem("Private"));
333             expected.addAll(PRIVATE_ITEMS);
334         }
335 
336         assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap))
337                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
338                 .containsExactlyElementsIn(expected)
339                 .inOrder();
340     }
341 
342     @Test
testCreatePresentableListForAllUsers_currentIsWork_allUsersItems()343     public void testCreatePresentableListForAllUsers_currentIsWork_allUsersItems() {
344         final List<List<Item>> rootListAllUsers = new ArrayList<>();
345         rootListAllUsers.add(PERSONAL_ITEMS);
346         rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS));
347         if (SdkLevel.isAtLeastV()) {
348             rootListAllUsers.add(PRIVATE_ITEMS);
349         }
350         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
351                 .overrideCurrentUserForTest(WORK_USER)
352                 .setRootListForAllUsers(rootListAllUsers);
353 
354         List<Item> expected = Lists.newArrayList();
355         expected.add(new HeaderItem("Personal"));
356         expected.addAll(PERSONAL_ITEMS);
357         expected.add(new HeaderItem("Work"));
358         expected.addAll(WORK_ITEMS);
359         if (SdkLevel.isAtLeastV()) {
360             expected.add(new HeaderItem("Private"));
361             expected.addAll(PRIVATE_ITEMS);
362         }
363 
364         assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap))
365                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
366                 .containsExactlyElementsIn(expected)
367                 .inOrder();
368     }
369 
370     @Test
testCreatePresentableListForAllUsers_currentIsPrivate_allUsersItems()371     public void testCreatePresentableListForAllUsers_currentIsPrivate_allUsersItems() {
372         final List<List<Item>> rootListAllUsers = new ArrayList<>();
373         rootListAllUsers.add(PERSONAL_ITEMS);
374         rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS));
375         if (SdkLevel.isAtLeastV()) {
376             rootListAllUsers.add(PRIVATE_ITEMS);
377         }
378         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
379                 .overrideCurrentUserForTest(PRIVATE_USER)
380                 .setRootListForAllUsers(rootListAllUsers);
381 
382         List<Item> expected = Lists.newArrayList();
383         expected.add(new HeaderItem("Personal"));
384         expected.addAll(PERSONAL_ITEMS);
385         expected.add(new HeaderItem("Work"));
386         expected.addAll(WORK_ITEMS);
387         if (SdkLevel.isAtLeastV()) {
388             expected.add(new HeaderItem("Private"));
389             expected.addAll(PRIVATE_ITEMS);
390         }
391 
392         assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap))
393                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
394                 .containsExactlyElementsIn(expected)
395                 .inOrder();
396     }
397 
398     @Test
testCreatePresentableList_currentIsPersonal_personalAndWorkItems_cannotShare()399     public void testCreatePresentableList_currentIsPersonal_personalAndWorkItems_cannotShare() {
400         mState.canShareAcrossProfile = false;
401         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
402                 .setRootListForCurrentUser(PERSONAL_ITEMS)
403                 .setRootListForOtherUser(WORK_ITEMS);
404 
405         assertThat(mCombiner.createPresentableList())
406                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
407                 .containsExactlyElementsIn(PERSONAL_ITEMS)
408                 .inOrder();
409     }
410 
411     @Test
testCreatePresentableList_currentIsWork_personalItemsOnly_cannotShare()412     public void testCreatePresentableList_currentIsWork_personalItemsOnly_cannotShare() {
413         mState.canShareAcrossProfile = false;
414         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
415                 .overrideCurrentUserForTest(WORK_USER)
416                 .setRootListForCurrentUser(Collections.emptyList())
417                 .setRootListForOtherUser(PERSONAL_ITEMS);
418 
419         assertThat(mCombiner.createPresentableList()).isEmpty();
420     }
421 
422     @Test
testCreatePresentableListForAllUsers_currentIsPersonal_cannotShareToWork()423     public void testCreatePresentableListForAllUsers_currentIsPersonal_cannotShareToWork() {
424         if (!SdkLevel.isAtLeastV()) return;
425         mState.canForwardToProfileIdMap.put(WORK_USER, false);
426         final List<List<Item>> rootListAllUsers = new ArrayList<>();
427         rootListAllUsers.add(PERSONAL_ITEMS);
428         rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS));
429         if (SdkLevel.isAtLeastV()) {
430             rootListAllUsers.add(PRIVATE_ITEMS);
431         }
432         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
433                 .setRootListForAllUsers(rootListAllUsers);
434 
435         List<Item> expected = Lists.newArrayList();
436         expected.add(new HeaderItem("Personal"));
437         expected.addAll(PERSONAL_ITEMS);
438         if (SdkLevel.isAtLeastV()) {
439             expected.add(new HeaderItem("Private"));
440             expected.addAll(PRIVATE_ITEMS);
441         }
442 
443         assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap))
444                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
445                 .containsExactlyElementsIn(expected)
446                 .inOrder();
447     }
448 
449     @Test
testCreatePresentableListForAllUsers_currentIsWork_AllItems_cannotSharePersonal()450     public void testCreatePresentableListForAllUsers_currentIsWork_AllItems_cannotSharePersonal() {
451         if (!SdkLevel.isAtLeastV()) return;
452         mState.canForwardToProfileIdMap.put(PERSONAL_USER, false);
453         // In the current implementation of cross profile content sharing strategy work profile will
454         // be able to share to all the child profiles of the parent/personal profile only if it is
455         // able to share with parent/personal profile
456         mState.canForwardToProfileIdMap.put(PRIVATE_USER, false);
457         final List<List<Item>> rootListAllUsers = new ArrayList<>();
458         rootListAllUsers.add(PERSONAL_ITEMS);
459         rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS));
460         if (SdkLevel.isAtLeastV()) {
461             rootListAllUsers.add(PRIVATE_ITEMS);
462         }
463         mCombiner = new UserItemsCombiner(mResources, mDpm, mState)
464                 .overrideCurrentUserForTest(WORK_USER)
465                 .setRootListForAllUsers(rootListAllUsers);
466 
467         assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap))
468                 .comparingElementsUsing(ITEM_CORRESPONDENCE)
469                 .containsExactlyElementsIn(WORK_ITEMS)
470                 .inOrder();
471     }
472 
personalItem(String title)473     private static TestItem personalItem(String title) {
474         return new TestItem(title, PERSONAL_USER);
475     }
476 
workItem(String title)477     private static TestItem workItem(String title) {
478         return new TestItem(title, WORK_USER);
479     }
480 
privateItem(String title)481     private static TestItem privateItem(String title) {
482         return new TestItem(title, PRIVATE_USER);
483     }
484 
485     private static class TestItem extends Item {
486 
TestItem(String title, UserId userId)487         TestItem(String title, UserId userId) {
488             super(/* layoutId= */ 0, title, /* stringId= */ "", userId);
489         }
490 
491         @Override
bindView(View convertView)492         void bindView(View convertView) {
493         }
494 
495         @Override
isRoot()496         boolean isRoot() {
497             return false;
498         }
499 
500         @Override
open()501         void open() {
502         }
503 
504         @Override
toString()505         public String toString() {
506             return title + "(" + userId + ")";
507         }
508     }
509 }
510