• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.settings.applications;
18 
19 import static android.app.AppOpsManager.MODE_ALLOWED;
20 import static android.app.AppOpsManager.MODE_DEFAULT;
21 import static android.app.AppOpsManager.MODE_ERRORED;
22 import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
23 
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertTrue;
27 
28 import android.app.AppOpsManager;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.pm.ApplicationInfo;
32 import android.content.pm.PackageManager;
33 import android.content.pm.UserInfo;
34 import android.net.Uri;
35 import android.os.UserHandle;
36 import android.os.UserManager;
37 import android.provider.Settings;
38 import android.support.test.InstrumentationRegistry;
39 import android.support.test.filters.LargeTest;
40 import android.support.test.runner.AndroidJUnit4;
41 import android.support.test.uiautomator.By;
42 import android.support.test.uiautomator.BySelector;
43 import android.support.test.uiautomator.Direction;
44 
45 import android.support.test.uiautomator.UiDevice;
46 import android.support.test.uiautomator.UiObject2;
47 import android.support.test.uiautomator.Until;
48 import android.widget.ListView;
49 import android.widget.Switch;
50 import android.widget.TextView;
51 
52 import org.junit.After;
53 import org.junit.Before;
54 import org.junit.Test;
55 import org.junit.runner.RunWith;
56 
57 import java.util.List;
58 
59 @RunWith(AndroidJUnit4.class)
60 @LargeTest
61 public class ExternalSourcesSettingsTest {
62 
63     private static final String TAG = ExternalSourcesSettingsTest.class.getSimpleName();
64     private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard";
65     private static final long START_ACTIVITY_TIMEOUT = 5000;
66 
67     private Context mContext;
68     private UiDevice mUiDevice;
69     private PackageManager mPackageManager;
70     private AppOpsManager mAppOpsManager;
71     private List<UserInfo> mProfiles;
72     private String mPackageName;
73 
74     @Before
setUp()75     public void setUp() throws Exception {
76         mContext = InstrumentationRegistry.getTargetContext();
77         mPackageName = InstrumentationRegistry.getContext().getPackageName();
78         mPackageManager = mContext.getPackageManager();
79         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
80         mProfiles = mContext.getSystemService(UserManager.class).getProfiles(UserHandle.myUserId());
81         resetAppOpModeForAllProfiles();
82         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
83         mUiDevice.wakeUp();
84         mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND);
85     }
86 
resetAppOpModeForAllProfiles()87     private void resetAppOpModeForAllProfiles() throws Exception {
88         for (UserInfo user : mProfiles) {
89             final int uid = mPackageManager.getPackageUidAsUser(mPackageName, user.id);
90             mAppOpsManager.setMode(OP_REQUEST_INSTALL_PACKAGES, uid, mPackageName, MODE_DEFAULT);
91         }
92     }
93 
createManageExternalSourcesListIntent()94     private Intent createManageExternalSourcesListIntent() {
95         final Intent manageExternalSourcesIntent = new Intent();
96         manageExternalSourcesIntent.setAction(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
97         return manageExternalSourcesIntent;
98     }
99 
createManageExternalSourcesAppIntent(String packageName)100     private Intent createManageExternalSourcesAppIntent(String packageName) {
101         final Intent intent = createManageExternalSourcesListIntent();
102         intent.setData(Uri.parse("package:" + packageName));
103         return intent;
104     }
105 
getApplicationLabel(String packageName)106     private String getApplicationLabel(String packageName) throws Exception {
107         final ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, 0);
108         return mPackageManager.getApplicationLabel(info).toString();
109     }
110 
findAndVerifySwitchState(boolean checked)111     private UiObject2 findAndVerifySwitchState(boolean checked) {
112         final BySelector switchSelector = By.clazz(Switch.class).res("android:id/switch_widget");
113         final UiObject2 switchPref = mUiDevice.wait(Until.findObject(switchSelector),
114                 START_ACTIVITY_TIMEOUT);
115         assertNotNull("Switch not shown", switchPref);
116         assertTrue("Switch in invalid state", switchPref.isChecked() == checked);
117         return switchPref;
118     }
119 
120     @Test
testManageExternalSourcesList()121     public void testManageExternalSourcesList() throws Exception {
122         final String testAppLabel = getApplicationLabel(mPackageName);
123 
124         mContext.startActivity(createManageExternalSourcesListIntent());
125         final BySelector preferenceListSelector = By.clazz(ListView.class).res("android:id/list");
126         final UiObject2 preferenceList = mUiDevice.wait(Until.findObject(preferenceListSelector),
127                 START_ACTIVITY_TIMEOUT);
128         assertNotNull("App list not shown", preferenceList);
129 
130         final BySelector appLabelTextViewSelector = By.clazz(TextView.class)
131                 .res("android:id/title")
132                 .text(testAppLabel);
133         List<UiObject2> listOfMatchingTextViews;
134         do {
135             listOfMatchingTextViews = preferenceList.findObjects(appLabelTextViewSelector);
136             // assuming the number of profiles will be sufficiently small so that all the entries
137             // for the same package will fit in one screen at some time during the scroll.
138         } while (listOfMatchingTextViews.size() != mProfiles.size() &&
139                 preferenceList.scroll(Direction.DOWN, 0.2f));
140         assertEquals("Test app not listed for each profile", mProfiles.size(),
141                 listOfMatchingTextViews.size());
142 
143         for (UiObject2 matchingObject : listOfMatchingTextViews) {
144             matchingObject.click();
145             findAndVerifySwitchState(true);
146             mUiDevice.pressBack();
147         }
148     }
149 
testAppDetailScreenForAppOp(int appOpMode, int userId)150     private void testAppDetailScreenForAppOp(int appOpMode, int userId) throws Exception {
151         final String testAppLabel = getApplicationLabel(mPackageName);
152         final BySelector appDetailTitleSelector = By.clazz(TextView.class)
153                 .res("com.android.settings:id/app_detail_title")
154                 .text(testAppLabel);
155 
156         mAppOpsManager.setMode(OP_REQUEST_INSTALL_PACKAGES,
157                 mPackageManager.getPackageUidAsUser(mPackageName, userId), mPackageName, appOpMode);
158         mContext.startActivityAsUser(createManageExternalSourcesAppIntent(mPackageName),
159                 UserHandle.of(userId));
160         mUiDevice.wait(Until.findObject(appDetailTitleSelector), START_ACTIVITY_TIMEOUT);
161         findAndVerifySwitchState(appOpMode == MODE_ALLOWED || appOpMode == MODE_DEFAULT);
162         mUiDevice.pressBack();
163     }
164 
165     @Test
testManageExternalSourcesForApp()166     public void testManageExternalSourcesForApp() throws Exception {
167         // App op MODE_DEFAULT is already tested in #testManageExternalSourcesList
168         for (UserInfo user : mProfiles) {
169             testAppDetailScreenForAppOp(MODE_ALLOWED, user.id);
170             testAppDetailScreenForAppOp(MODE_ERRORED, user.id);
171         }
172     }
173 
testSwitchToggle(int fromAppOp, int toAppOp)174     private void testSwitchToggle(int fromAppOp, int toAppOp) throws Exception {
175         final int packageUid = mPackageManager.getPackageUid(mPackageName, 0);
176         final boolean initialState = (fromAppOp == MODE_ALLOWED || fromAppOp == MODE_DEFAULT);
177 
178         mAppOpsManager.setMode(OP_REQUEST_INSTALL_PACKAGES, packageUid, mPackageName, fromAppOp);
179         mContext.startActivity(createManageExternalSourcesAppIntent(mPackageName));
180         final UiObject2 switchPref = findAndVerifySwitchState(initialState);
181         switchPref.click();
182         Thread.sleep(1000);
183         assertEquals("Toggling switch did not change app op", toAppOp,
184                 mAppOpsManager.checkOpNoThrow(OP_REQUEST_INSTALL_PACKAGES, packageUid,
185                         mPackageName));
186         mUiDevice.pressBack();
187     }
188 
189     @Test
testIfSwitchTogglesAppOp()190     public void testIfSwitchTogglesAppOp() throws Exception {
191         testSwitchToggle(MODE_ALLOWED, MODE_ERRORED);
192         testSwitchToggle(MODE_ERRORED, MODE_ALLOWED);
193     }
194 
195     @After
tearDown()196     public void tearDown() throws Exception {
197         mUiDevice.pressHome();
198         resetAppOpModeForAllProfiles();
199     }
200 }
201