1 /*
2  * Copyright (C) 2021 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.systemui.people;
18 
19 import static com.android.systemui.people.PeopleBackupFollowUpJob.SHARED_FOLLOW_UP;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static org.mockito.ArgumentMatchers.any;
24 import static org.mockito.ArgumentMatchers.anyInt;
25 import static org.mockito.Mockito.times;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.when;
28 
29 import android.app.job.JobScheduler;
30 import android.app.people.IPeopleManager;
31 import android.content.Context;
32 import android.content.SharedPreferences;
33 import android.content.pm.PackageInfo;
34 import android.content.pm.PackageManager;
35 import android.net.Uri;
36 import android.os.RemoteException;
37 import android.preference.PreferenceManager;
38 import android.testing.AndroidTestingRunner;
39 
40 import androidx.test.filters.SmallTest;
41 
42 import com.android.systemui.SysuiTestCase;
43 import com.android.systemui.people.widget.PeopleTileKey;
44 
45 import org.junit.After;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.junit.runner.RunWith;
49 import org.mockito.Mock;
50 import org.mockito.MockitoAnnotations;
51 
52 import java.time.Duration;
53 import java.util.Arrays;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.Map;
57 import java.util.Set;
58 
59 @RunWith(AndroidTestingRunner.class)
60 @SmallTest
61 public class PeopleBackupFollowUpJobTest extends SysuiTestCase {
62     private static final String SHORTCUT_ID_1 = "101";
63     private static final String PACKAGE_NAME_1 = "package_name";
64     private static final int USER_ID_1 = 0;
65 
66     private static final PeopleTileKey PEOPLE_TILE_KEY =
67             new PeopleTileKey(SHORTCUT_ID_1, USER_ID_1, PACKAGE_NAME_1);
68 
69     private static final String WIDGET_ID_STRING = "3";
70     private static final String SECOND_WIDGET_ID_STRING = "12";
71     private static final Set<String> WIDGET_IDS = new HashSet<>(
72             Arrays.asList(WIDGET_ID_STRING, SECOND_WIDGET_ID_STRING));
73 
74     private static final Uri URI = Uri.parse("fake_uri");
75 
76     @Mock
77     private PackageManager mPackageManager;
78     @Mock
79     private PackageInfo mPackageInfo;
80     @Mock
81     private IPeopleManager mIPeopleManager;
82     @Mock
83     private JobScheduler mJobScheduler;
84 
85     private final SharedPreferences mSp = PreferenceManager.getDefaultSharedPreferences(mContext);
86     private final SharedPreferences.Editor mEditor = mSp.edit();
87     private final SharedPreferences mFollowUpSp = mContext.getSharedPreferences(
88             SHARED_FOLLOW_UP, Context.MODE_PRIVATE);
89     private final SharedPreferences.Editor mFollowUpEditor = mFollowUpSp.edit();
90     private final SharedPreferences mWidgetIdSp = mContext.getSharedPreferences(
91             WIDGET_ID_STRING, Context.MODE_PRIVATE);
92     private final SharedPreferences mSecondWidgetIdSp = mContext.getSharedPreferences(
93             SECOND_WIDGET_ID_STRING, Context.MODE_PRIVATE);
94 
95     private PeopleBackupFollowUpJob mPeopleBackupFollowUpJob;
96 
97     @Before
setUp()98     public void setUp() throws Exception {
99         MockitoAnnotations.initMocks(this);
100 
101         when(mPackageManager.getPackageInfoAsUser(any(), anyInt(), anyInt()))
102                 .thenReturn(mPackageInfo);
103         when(mIPeopleManager.isConversation(any(), anyInt(), any())).thenReturn(true);
104 
105         mPeopleBackupFollowUpJob = new PeopleBackupFollowUpJob();
106         mPeopleBackupFollowUpJob.setManagers(
107                 mContext, mPackageManager, mIPeopleManager, mJobScheduler);
108     }
109 
110     @After
tearDown()111     public void tearDown() {
112         mEditor.clear().commit();
113         mFollowUpEditor.clear().commit();
114         mWidgetIdSp.edit().clear().commit();
115         mSecondWidgetIdSp.edit().clear().commit();
116     }
117 
118     @Test
testProcessFollowUpFile_shouldFollowUp()119     public void testProcessFollowUpFile_shouldFollowUp() throws RemoteException {
120         when(mIPeopleManager.isConversation(any(), anyInt(), any())).thenReturn(false);
121         mFollowUpEditor.putStringSet(PEOPLE_TILE_KEY.toString(), WIDGET_IDS);
122         mFollowUpEditor.apply();
123 
124         Map<String, Set<String>> remainingWidgets =
125                 mPeopleBackupFollowUpJob.processFollowUpFile(mFollowUpSp, mFollowUpEditor);
126         mEditor.apply();
127         mFollowUpEditor.apply();
128 
129         assertThat(remainingWidgets.size()).isEqualTo(1);
130         assertThat(remainingWidgets.get(PEOPLE_TILE_KEY.toString()))
131                 .containsExactly(WIDGET_ID_STRING, SECOND_WIDGET_ID_STRING);
132         assertThat(mFollowUpSp.getStringSet(PEOPLE_TILE_KEY.toString(), new HashSet<>()))
133                 .containsExactly(WIDGET_ID_STRING, SECOND_WIDGET_ID_STRING);
134     }
135 
136     @Test
testProcessFollowUpFile_shouldRestore()137     public void testProcessFollowUpFile_shouldRestore() {
138         mFollowUpEditor.putStringSet(PEOPLE_TILE_KEY.toString(), WIDGET_IDS);
139         mFollowUpEditor.apply();
140 
141         Map<String, Set<String>> remainingWidgets =
142                 mPeopleBackupFollowUpJob.processFollowUpFile(mFollowUpSp, mFollowUpEditor);
143         mEditor.apply();
144         mFollowUpEditor.apply();
145 
146         assertThat(remainingWidgets).isEmpty();
147         assertThat(mFollowUpSp.getStringSet(PEOPLE_TILE_KEY.toString(), new HashSet<>())).isEmpty();
148     }
149 
150     @Test
testShouldCancelJob_noRemainingWidgets_shouldCancel()151     public void testShouldCancelJob_noRemainingWidgets_shouldCancel() {
152         assertThat(mPeopleBackupFollowUpJob.shouldCancelJob(
153                 new HashMap<>(), 10, Duration.ofMinutes(1).toMillis())).isTrue();
154     }
155 
156     @Test
testShouldCancelJob_noRemainingWidgets_longTimeElapsed_shouldCancel()157     public void testShouldCancelJob_noRemainingWidgets_longTimeElapsed_shouldCancel() {
158         assertThat(mPeopleBackupFollowUpJob.shouldCancelJob(
159                 new HashMap<>(), 10, Duration.ofHours(50).toMillis())).isTrue();
160     }
161 
162     @Test
testShouldCancelJob_remainingWidgets_shortTimeElapsed_shouldNotCancel()163     public void testShouldCancelJob_remainingWidgets_shortTimeElapsed_shouldNotCancel() {
164         Map<String, Set<String>> remainingWidgets = new HashMap<>();
165         remainingWidgets.put(PEOPLE_TILE_KEY.toString(), WIDGET_IDS);
166         assertThat(mPeopleBackupFollowUpJob.shouldCancelJob(remainingWidgets, 10, 1000)).isFalse();
167     }
168 
169     @Test
testShouldCancelJob_remainingWidgets_longTimeElapsed_shouldCancel()170     public void testShouldCancelJob_remainingWidgets_longTimeElapsed_shouldCancel() {
171         Map<String, Set<String>> remainingWidgets = new HashMap<>();
172         remainingWidgets.put(PEOPLE_TILE_KEY.toString(), WIDGET_IDS);
173         assertThat(mPeopleBackupFollowUpJob.shouldCancelJob(
174                 remainingWidgets, 10, Duration.ofHours(50).toMillis())).isTrue();
175     }
176 
177     @Test
testCancelJobAndClearRemainingWidgets()178     public void testCancelJobAndClearRemainingWidgets() {
179         SharedPreferencesHelper.setPeopleTileKey(mWidgetIdSp, PEOPLE_TILE_KEY);
180         SharedPreferencesHelper.setPeopleTileKey(mSecondWidgetIdSp, PEOPLE_TILE_KEY);
181         mEditor.putStringSet(URI.toString(), WIDGET_IDS);
182         mEditor.putString(WIDGET_ID_STRING, URI.toString());
183         mEditor.putString(SECOND_WIDGET_ID_STRING, URI.toString());
184         mEditor.apply();
185         Map<String, Set<String>> remainingWidgets = new HashMap<>();
186         remainingWidgets.put(PEOPLE_TILE_KEY.toString(), WIDGET_IDS);
187 
188         mPeopleBackupFollowUpJob.cancelJobAndClearRemainingWidgets(
189                 remainingWidgets, mFollowUpEditor, mSp);
190         mEditor.apply();
191         mFollowUpEditor.apply();
192 
193         verify(mJobScheduler, times(1)).cancel(anyInt());
194         assertThat(mFollowUpSp.getAll()).isEmpty();
195         assertThat(mWidgetIdSp.getAll()).isEmpty();
196         assertThat(mSecondWidgetIdSp.getAll()).isEmpty();
197         assertThat(mSp.getStringSet(PEOPLE_TILE_KEY.toString(), new HashSet<>())).isEmpty();
198         assertThat(mSp.getStringSet(URI.toString(), new HashSet<>())).isEmpty();
199         assertThat(mSp.getString(WIDGET_ID_STRING, null)).isNull();
200         assertThat(mSp.getString(SECOND_WIDGET_ID_STRING, null)).isNull();
201     }
202 }
203