1 /*
2  * Copyright (C) 2016 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.settings.applications;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.verify;
24 import static org.mockito.Mockito.when;
25 
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.pm.ApplicationInfo;
30 import android.content.pm.PackageInfo;
31 import android.content.pm.PackageManager;
32 import android.net.Uri;
33 import android.os.UserHandle;
34 
35 import androidx.appcompat.app.AlertDialog;
36 import androidx.preference.PreferenceManager;
37 import androidx.preference.PreferenceScreen;
38 
39 import com.android.internal.logging.nano.MetricsProto;
40 import com.android.settings.testutils.FakeFeatureFactory;
41 import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
42 import com.android.settings.testutils.shadow.ShadowSettingsLibUtils;
43 import com.android.settings.widget.EntityHeaderController;
44 import com.android.settingslib.applications.AppUtils;
45 import com.android.settingslib.applications.ApplicationsState;
46 import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
47 import com.android.settingslib.widget.LayoutPreference;
48 
49 import org.junit.After;
50 import org.junit.Before;
51 import org.junit.Test;
52 import org.junit.runner.RunWith;
53 import org.mockito.Answers;
54 import org.mockito.Mock;
55 import org.mockito.MockitoAnnotations;
56 import org.robolectric.RobolectricTestRunner;
57 import org.robolectric.RuntimeEnvironment;
58 import org.robolectric.annotation.Config;
59 import org.robolectric.util.ReflectionHelpers;
60 
61 @RunWith(RobolectricTestRunner.class)
62 @Config(shadows = {ShadowEntityHeaderController.class, ShadowSettingsLibUtils.class})
63 public class AppInfoWithHeaderTest {
64 
65     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
66     private EntityHeaderController mHeaderController;
67 
68     private FakeFeatureFactory mFactory;
69     private TestFragment mAppInfoWithHeader;
70 
71     @Before
setUp()72     public void setUp() {
73         MockitoAnnotations.initMocks(this);
74         mFactory = FakeFeatureFactory.setupForTest();
75         when(mFactory.metricsFeatureProvider.getMetricsCategory(any(Object.class)))
76                 .thenReturn(MetricsProto.MetricsEvent.SETTINGS_APP_NOTIF_CATEGORY);
77         mAppInfoWithHeader = new TestFragment();
78         ShadowEntityHeaderController.setUseMock(mHeaderController);
79     }
80 
81     @After
tearDown()82     public void tearDown() {
83         ShadowEntityHeaderController.reset();
84     }
85 
86     @Test
testAppHeaderIsAdded()87     public void testAppHeaderIsAdded() {
88         mAppInfoWithHeader.onActivityCreated(null);
89 
90         verify(mAppInfoWithHeader.mScreen).addPreference(any(LayoutPreference.class));
91     }
92 
93     @Test
packageRemoved_noAppEntry_shouldFinishActivity()94     public void packageRemoved_noAppEntry_shouldFinishActivity() {
95         BroadcastReceiver packageRemovedReceiver =
96                 ReflectionHelpers.getField(mAppInfoWithHeader, "mPackageRemovedReceiver");
97         ReflectionHelpers.setField(mAppInfoWithHeader, "mAppEntry", null);
98 
99         final Intent packageRemovedBroadcast = new Intent();
100         packageRemovedBroadcast.setData(Uri.parse("package:com.android.settings"));
101         packageRemovedReceiver.onReceive(RuntimeEnvironment.application, packageRemovedBroadcast);
102 
103         assertThat(mAppInfoWithHeader.mPackageRemovedCalled).isTrue();
104     }
105 
106     @Test
packageRemoved_appEntryMatchesPackageName_shouldFinishActivity()107     public void packageRemoved_appEntryMatchesPackageName_shouldFinishActivity() {
108         BroadcastReceiver packageRemovedReceiver =
109                 ReflectionHelpers.getField(mAppInfoWithHeader, "mPackageRemovedReceiver");
110         final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
111         entry.info = new ApplicationInfo();
112         entry.info.packageName = "com.android.settings";
113         ReflectionHelpers.setField(mAppInfoWithHeader, "mAppEntry", entry);
114 
115         final Intent packageRemovedBroadcast = new Intent();
116         packageRemovedBroadcast.setData(Uri.parse("package:" + entry.info.packageName));
117         packageRemovedReceiver.onReceive(RuntimeEnvironment.application, packageRemovedBroadcast);
118 
119         assertThat(mAppInfoWithHeader.mPackageRemovedCalled).isTrue();
120     }
121 
122     @Test
noExtraUserHandleInIntent_retrieveAppEntryWithMyUserId()123     public void noExtraUserHandleInIntent_retrieveAppEntryWithMyUserId()
124             throws PackageManager.NameNotFoundException {
125         final String packageName = "com.android.settings";
126 
127         mAppInfoWithHeader.mIntent.setData(Uri.fromParts("package", packageName, null));
128         final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
129         entry.info = new ApplicationInfo();
130         entry.info.packageName = packageName;
131 
132         when(mAppInfoWithHeader.mState.getEntry(packageName,
133                 UserHandle.myUserId())).thenReturn(entry);
134         when(mAppInfoWithHeader.mPm.getPackageInfoAsUser(entry.info.packageName,
135                 PackageManager.MATCH_DISABLED_COMPONENTS |
136                         PackageManager.GET_SIGNING_CERTIFICATES |
137                         PackageManager.GET_PERMISSIONS, UserHandle.myUserId())).thenReturn(
138                 mAppInfoWithHeader.mPackageInfo);
139 
140         mAppInfoWithHeader.retrieveAppEntry();
141 
142         assertThat(mAppInfoWithHeader.mUserId).isEqualTo(UserHandle.myUserId());
143         assertThat(mAppInfoWithHeader.mPackageInfo).isNotNull();
144         assertThat(mAppInfoWithHeader.mAppEntry).isNotNull();
145     }
146 
147     @Test
extraUserHandleInIntent_retrieveAppEntryWithMyUserId()148     public void extraUserHandleInIntent_retrieveAppEntryWithMyUserId()
149             throws PackageManager.NameNotFoundException {
150         final int USER_ID = 1002;
151         final String packageName = "com.android.settings";
152 
153         mAppInfoWithHeader.mIntent.putExtra(Intent.EXTRA_USER_HANDLE, new UserHandle(USER_ID));
154         mAppInfoWithHeader.mIntent.setData(Uri.fromParts("package",
155                 packageName, null));
156         final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
157         entry.info = new ApplicationInfo();
158         entry.info.packageName = packageName;
159 
160         when(mAppInfoWithHeader.mState.getEntry(packageName, USER_ID)).thenReturn(entry);
161         when(mAppInfoWithHeader.mPm.getPackageInfoAsUser(entry.info.packageName,
162                 PackageManager.MATCH_DISABLED_COMPONENTS |
163                         PackageManager.GET_SIGNING_CERTIFICATES |
164                         PackageManager.GET_PERMISSIONS, USER_ID)).thenReturn(
165                 mAppInfoWithHeader.mPackageInfo);
166 
167         mAppInfoWithHeader.retrieveAppEntry();
168 
169         assertThat(mAppInfoWithHeader.mUserId).isEqualTo(USER_ID);
170         assertThat(mAppInfoWithHeader.mPackageInfo).isNotNull();
171         assertThat(mAppInfoWithHeader.mAppEntry).isNotNull();
172     }
173 
174     public static class TestFragment extends AppInfoWithHeader {
175 
176         PreferenceManager mManager;
177         PreferenceScreen mScreen;
178         Context mShadowContext;
179         boolean mPackageRemovedCalled;
180         Intent mIntent;
181 
TestFragment()182         public TestFragment() {
183             mPm = mock(PackageManager.class);
184             mManager = mock(PreferenceManager.class);
185             mScreen = mock(PreferenceScreen.class);
186             mPackageInfo = new PackageInfo();
187             mPackageInfo.applicationInfo = new ApplicationInfo();
188             mState = mock(ApplicationsState.class);
189             mIntent = new Intent();
190             mShadowContext = RuntimeEnvironment.application;
191             ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
192                     (InstantAppDataProvider) (info -> false));
193             when(mManager.getContext()).thenReturn(mShadowContext);
194         }
195 
196         @Override
getMetricsCategory()197         public int getMetricsCategory() {
198             return 0;
199         }
200 
201         @Override
refreshUi()202         protected boolean refreshUi() {
203             return false;
204         }
205 
206         @Override
createDialog(int id, int errorCode)207         protected AlertDialog createDialog(int id, int errorCode) {
208             return null;
209         }
210 
211         @Override
getPreferenceScreen()212         public PreferenceScreen getPreferenceScreen() {
213             return mScreen;
214         }
215 
216         @Override
getPreferenceManager()217         public PreferenceManager getPreferenceManager() {
218             return mManager;
219         }
220 
221         @Override
getContext()222         public Context getContext() {
223             return mShadowContext;
224         }
225 
226         @Override
onPackageRemoved()227         protected void onPackageRemoved() {
228             mPackageRemovedCalled = true;
229         }
230 
231         @Override
getIntent()232         protected Intent getIntent() { return mIntent; }
233     }
234 }
235