1 /*
2  * Copyright (C) 2018 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.fuelgauge;
18 
19 import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT;
20 import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID;
21 
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.Mockito.doReturn;
26 import static org.mockito.Mockito.mock;
27 import static org.mockito.Mockito.spy;
28 import static org.mockito.Mockito.verify;
29 import static org.mockito.Mockito.when;
30 
31 import android.app.Activity;
32 import android.app.AppOpsManager;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.os.UserHandle;
36 import android.os.UserManager;
37 import android.util.Pair;
38 
39 import androidx.preference.Preference;
40 import androidx.preference.PreferenceManager;
41 import androidx.preference.PreferenceScreen;
42 
43 import com.android.settings.R;
44 import com.android.settings.core.InstrumentedPreferenceFragment;
45 import com.android.settings.fuelgauge.batterytip.AppInfo;
46 
47 import org.junit.Before;
48 import org.junit.Test;
49 import org.junit.runner.RunWith;
50 import org.mockito.ArgumentCaptor;
51 import org.mockito.Mock;
52 import org.mockito.MockitoAnnotations;
53 import org.robolectric.Robolectric;
54 import org.robolectric.RobolectricTestRunner;
55 
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.List;
59 
60 @RunWith(RobolectricTestRunner.class)
61 public class RestrictAppPreferenceControllerTest {
62     private static final int ALLOWED_UID = 111;
63     private static final String ALLOWED_PACKAGE_NAME = "com.android.allowed.package";
64     private static final int RESTRICTED_UID = 222;
65     private static final String RESTRICTED_PACKAGE_NAME = "com.android.restricted.package";
66     private static final int OTHER_USER_UID = UserHandle.PER_USER_RANGE + RESTRICTED_UID;
67 
68     @Mock
69     private AppOpsManager mAppOpsManager;
70     @Mock
71     private InstrumentedPreferenceFragment mFragment;
72     @Mock
73     private UserManager mUserManager;
74 
75     private AppOpsManager.PackageOps mRestrictedPackageOps;
76     private AppOpsManager.PackageOps mAllowedPackageOps;
77     private AppOpsManager.PackageOps mOtherUserPackageOps;
78     private List<AppOpsManager.PackageOps> mPackageOpsList;
79     private Preference mPreference;
80     private PreferenceScreen mPreferenceScreen;
81     private Context mContext;
82 
83     @Before
setUp()84     public void setUp() {
85         MockitoAnnotations.initMocks(this);
86         final List<AppOpsManager.OpEntry> allowOps = new ArrayList<>();
87         allowOps.add(new AppOpsManager.OpEntry(
88                 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, AppOpsManager.MODE_ALLOWED,
89                 Collections.emptyMap()));
90         final List<AppOpsManager.OpEntry> restrictedOps = new ArrayList<>();
91         restrictedOps.add(new AppOpsManager.OpEntry(
92                 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, AppOpsManager.MODE_IGNORED,
93                 Collections.emptyMap()));
94         mAllowedPackageOps = new AppOpsManager.PackageOps(
95                 ALLOWED_PACKAGE_NAME, ALLOWED_UID, allowOps);
96         mRestrictedPackageOps = new AppOpsManager.PackageOps(
97                 RESTRICTED_PACKAGE_NAME, RESTRICTED_UID, restrictedOps);
98         mOtherUserPackageOps = new AppOpsManager.PackageOps(
99                 RESTRICTED_PACKAGE_NAME, OTHER_USER_UID, restrictedOps);
100 
101         mContext = spy(Robolectric.setupActivity(Activity.class));
102         doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE);
103         doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
104         doReturn(mContext).when(mFragment).getContext();
105 
106         mPackageOpsList = new ArrayList<>();
107         mPreference = new Preference(mContext);
108         mPreference.setKey(RestrictAppPreferenceController.KEY_RESTRICT_APP);
109         mPreferenceScreen = spy(new PreferenceScreen(mContext, null));
110         when(mPreferenceScreen.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
111         when(mPreferenceScreen.getContext()).thenReturn(mContext);
112         when(mPreferenceScreen.findPreference(
113                 RestrictAppPreferenceController.KEY_RESTRICT_APP)).thenReturn(mPreference);
114 
115         final List<UserHandle> userHandles = new ArrayList<>();
116         userHandles.add(new UserHandle(0));
117         doReturn(userHandles).when(mUserManager).getUserProfiles();
118     }
119 
120     @Test
updateState_oneApp_showCorrectSummary()121     public void updateState_oneApp_showCorrectSummary() {
122         mPackageOpsList.add(mRestrictedPackageOps);
123         doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));
124 
125         final RestrictAppPreferenceController controller = new RestrictAppPreferenceController(
126                 mFragment);
127         controller.displayPreference(mPreferenceScreen);
128         controller.updateState(mPreference);
129 
130         assertThat(mPreference.getSummary()).isEqualTo("Limiting battery usage for 1 app");
131     }
132 
133     @Test
updateState_twoRestrictedAppsForPrimaryUser_visibleAndShowCorrectSummary()134     public void updateState_twoRestrictedAppsForPrimaryUser_visibleAndShowCorrectSummary() {
135         mPackageOpsList.add(mRestrictedPackageOps);
136         mPackageOpsList.add(mRestrictedPackageOps);
137         mPackageOpsList.add(mAllowedPackageOps);
138         mPackageOpsList.add(mOtherUserPackageOps);
139         doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));
140 
141         final RestrictAppPreferenceController controller = new RestrictAppPreferenceController(
142                 mFragment);
143         controller.displayPreference(mPreferenceScreen);
144         controller.updateState(mPreference);
145 
146         assertThat(mPreference.getSummary()).isEqualTo("Limiting battery usage for 2 apps");
147         assertThat(mPreference.isVisible()).isTrue();
148     }
149 
150     @Test
updateState_oneRestrictedAppForTwoUsers_showSummaryAndContainCorrectApp()151     public void updateState_oneRestrictedAppForTwoUsers_showSummaryAndContainCorrectApp() {
152         // Two packageOps share same package name but different uid.
153         mPackageOpsList.add(mRestrictedPackageOps);
154         mPackageOpsList.add(mOtherUserPackageOps);
155         doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));
156 
157         final RestrictAppPreferenceController controller = new RestrictAppPreferenceController(
158                 mFragment);
159         controller.displayPreference(mPreferenceScreen);
160         controller.updateState(mPreference);
161 
162         assertThat(mPreference.getSummary()).isEqualTo("Limiting battery usage for 1 app");
163         assertThat(controller.mAppInfos).containsExactly(
164                 new AppInfo.Builder()
165                         .setUid(RESTRICTED_UID)
166                         .setPackageName(RESTRICTED_PACKAGE_NAME)
167                         .build());
168     }
169 
170     @Test
updateState_zeroRestrictApp_inVisible()171     public void updateState_zeroRestrictApp_inVisible() {
172         mPackageOpsList.add(mAllowedPackageOps);
173         doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));
174 
175         final RestrictAppPreferenceController controller = new RestrictAppPreferenceController(
176                 mFragment);
177         controller.displayPreference(mPreferenceScreen);
178         controller.updateState(mPreference);
179 
180         assertThat(mPreference.isVisible()).isFalse();
181     }
182 
183     @Test
handlePreferenceTreeClick_startFragment()184     public void handlePreferenceTreeClick_startFragment() {
185         final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
186 
187         final RestrictAppPreferenceController controller = new RestrictAppPreferenceController(
188                 mFragment);
189         controller.handlePreferenceTreeClick(mPreference);
190 
191         verify(mContext).startActivity(intent.capture());
192         assertThat(intent.getValue().getStringExtra(EXTRA_SHOW_FRAGMENT))
193                 .isEqualTo(RestrictedAppDetails.class.getName());
194         assertThat(intent.getValue().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, -1))
195                 .isEqualTo(R.string.restricted_app_title);
196     }
197 }
198