• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 package com.google.android.cts.deviceowner;
17 
18 import static android.server.wm.WindowManagerState.STATE_RESUMED;
19 
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import android.app.admin.DeviceAdminReceiver;
23 import android.app.admin.DevicePolicyManager;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.pm.PackageManager;
28 import android.os.RemoteException;
29 import android.os.UserHandle;
30 import android.provider.Settings;
31 import android.server.wm.WindowManagerStateHelper;
32 import android.test.InstrumentationTestCase;
33 import android.util.Log;
34 
35 import androidx.test.InstrumentationRegistry;
36 import androidx.test.uiautomator.By;
37 import androidx.test.uiautomator.UiDevice;
38 import androidx.test.uiautomator.UiObjectNotFoundException;
39 import androidx.test.uiautomator.UiScrollable;
40 import androidx.test.uiautomator.UiSelector;
41 import androidx.test.uiautomator.Until;
42 
43 import com.android.bedstead.dpmwrapper.DeviceOwnerHelper;
44 import com.android.bedstead.dpmwrapper.TestAppSystemServiceFactory;
45 import com.android.compatibility.common.util.enterprise.DeviceAdminReceiverUtils;
46 
47 /**
48  * Class for device-owner based tests.
49  *
50  * <p>This class handles making sure that the test is the device owner and that it has an active
51  * admin registered if necessary. The admin component can be accessed through {@link #getWho()}.
52  */
53 public final class DeviceOwnerTest extends InstrumentationTestCase {
54 
55     private static final String TAG = DeviceOwnerTest.class.getSimpleName();
56 
57     public static final int TIMEOUT_MS = 2_000;
58 
59     public static final double DEADZONE_PCT = 0.2;
60 
61     protected Context mContext;
62     protected UiDevice mDevice;
63 
64     /** Device Admin receiver for DO. */
65     public static final class BasicAdminReceiver extends DeviceAdminReceiver {
66 
67         @Override
onReceive(Context context, Intent intent)68         public void onReceive(Context context, Intent intent) {
69             // Ignore intents used by DpmWrapper IPC between current and system users
70             if (DeviceOwnerHelper.runManagerMethod(this, context, intent)) return;
71 
72             // Hack used to manually disable the admin during development
73             if (DeviceAdminReceiverUtils.disableSelf(context, intent)) return;
74 
75             super.onReceive(context, intent);
76         }
77     }
78 
79     static final String CAR_SETTING_FRAG_RESOURCE_ID_REGEX = ".*:id/fragment_container_wrapper";
80     static final String PACKAGE_NAME = DeviceOwnerTest.class.getPackage().getName();
81     static final ComponentName RECEIVER_COMPONENT =
82             new ComponentName(PACKAGE_NAME, BasicAdminReceiver.class.getName());
83 
84     protected DevicePolicyManager mDevicePolicyManager;
85     protected PackageManager mPackageManager;
86     protected boolean mIsDeviceOwner;
87     private String mWorkPolicyInfoText;
88     private boolean mIsAutomotive;
89 
90     @Override
setUp()91     protected void setUp() throws Exception {
92         super.setUp();
93         mContext = getInstrumentation().getContext();
94         mDevice = UiDevice.getInstance(getInstrumentation());
95         mPackageManager = mContext.getPackageManager();
96         mDevicePolicyManager = TestAppSystemServiceFactory.getDevicePolicyManager(mContext,
97                 BasicAdminReceiver.class, /* forDeviceOwner= */ true);
98 
99         mIsAutomotive = mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
100 
101         mWorkPolicyInfoText = mIsAutomotive
102                 ? "Privacy Settings for Device Owner CTS host side app vehicle policy"
103                 : "Your work policy info";
104 
105         mIsDeviceOwner = mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME);
106         Log.d(TAG, "setup(): dpm=" + mDevicePolicyManager + ", isDO: " + mIsDeviceOwner);
107 
108         if (mIsDeviceOwner) {
109             assertWithMessage("isAdminActive(%s)", RECEIVER_COMPONENT)
110                     .that(mDevicePolicyManager.isAdminActive(RECEIVER_COMPONENT)).isTrue();
111 
112             // Note DPM.getDeviceOwner() now always returns null on non-DO users as of NYC.
113             assertWithMessage("%s.getDeviceOwner()", mDevicePolicyManager)
114                     .that(mDevicePolicyManager.getDeviceOwner()).isEqualTo(PACKAGE_NAME);
115         }
116 
117         try {
118             mDevice.setOrientationNatural();
119         } catch (RemoteException e) {
120             throw new RuntimeException("failed to freeze device orientation", e);
121         }
122         wakeupDeviceAndPressHome();
123     }
124 
wakeupDeviceAndPressHome()125     private void wakeupDeviceAndPressHome() throws Exception {
126         mDevice.wakeUp();
127         mDevice.pressMenu();
128         mDevice.pressHome();
129     }
130 
131     @Override
tearDown()132     protected void tearDown() throws Exception {
133         mDevice.pressBack();
134         mDevice.pressHome();
135         mDevice.waitForIdle(TIMEOUT_MS); // give UI time to finish animating
136     }
137 
launchPrivacyAndCheckWorkPolicyInfo()138     private boolean launchPrivacyAndCheckWorkPolicyInfo() throws Exception {
139         // Launch Settings
140         launchSettingsPage(InstrumentationRegistry.getContext(), Settings.ACTION_PRIVACY_SETTINGS);
141 
142         // Wait for loading permission usage data.
143         mDevice.waitForIdle(TIMEOUT_MS);
144 
145         Log.d(TAG, "Waiting " + TIMEOUT_MS + "ms for the '" + mWorkPolicyInfoText + "' message");
146 
147         boolean found = null != mDevice.wait(Until.findObject(By.text(mWorkPolicyInfoText)),
148                 TIMEOUT_MS);
149 
150         // For automotive and Safety Center UI, try to scroll the privacy list to find the item
151         if (!found) {
152             UiScrollable scroller;
153             if (mIsAutomotive) {
154                 scroller = new UiScrollable(new UiSelector()
155                         .resourceIdMatches(CAR_SETTING_FRAG_RESOURCE_ID_REGEX));
156             } else {
157                 scroller = new UiScrollable(new UiSelector().scrollable(true));
158             }
159             try {
160                 // Swipe far away from the edges to avoid triggering navigation gestures
161                 scroller.setSwipeDeadZonePercentage(DEADZONE_PCT);
162                 found = scroller.scrollTextIntoView(mWorkPolicyInfoText);
163             } catch (UiObjectNotFoundException e) { }
164         }
165 
166         Log.d(TAG, "Message found: " + found);
167         return found;
168     }
169 
launchSettingsPage(Context ctx, String pageName)170     private void launchSettingsPage(Context ctx, String pageName) throws Exception {
171         Intent intent = new Intent(pageName);
172         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
173 
174         Log.d(TAG, "Launching settings page on user " + UserHandle.myUserId() + " using " + intent);
175         ctx.startActivity(intent);
176 
177         ComponentName componentName =
178                 ctx.getPackageManager()
179                         .resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)
180                         .getComponentInfo()
181                         .getComponentName();
182 
183         Log.d(TAG, "Waiting for STATE_RESUMED on " + componentName);
184 
185         new WindowManagerStateHelper().waitForActivityState(componentName, STATE_RESUMED);
186     }
187 
disableWorkPolicyInfoActivity()188     private void disableWorkPolicyInfoActivity() {
189         mContext.getPackageManager()
190                 .setComponentEnabledSetting(
191                         new ComponentName(mContext, WorkPolicyInfoActivity.class),
192                         PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
193                         PackageManager.DONT_KILL_APP);
194     }
195 
launchPrivacySettingsAndAssertWorkPolicyInfoIsShowing()196     private void launchPrivacySettingsAndAssertWorkPolicyInfoIsShowing() throws Exception {
197         assertWithMessage("Work policy info (%s) on settings entry", mWorkPolicyInfoText)
198                 .that(launchPrivacyAndCheckWorkPolicyInfo()).isTrue();
199     }
200 
launchPrivacySettingsAndAssertWorkPolicyInfoIsNotShowing()201     private void launchPrivacySettingsAndAssertWorkPolicyInfoIsNotShowing() throws Exception {
202         assertWithMessage("Work policy info (%s) on settings entry", mWorkPolicyInfoText)
203                 .that(launchPrivacyAndCheckWorkPolicyInfo()).isFalse();
204     }
205 
206     /**
207      * If the app is the active device owner and has work policy info, then we should have a Privacy
208      * entry for it.
209      */
testDeviceOwnerWithInfo()210     public void testDeviceOwnerWithInfo() throws Exception {
211         assertWithMessage("is device owner").that(mIsDeviceOwner).isTrue();
212 
213         launchPrivacySettingsAndAssertWorkPolicyInfoIsShowing();
214     }
215 
216     /**
217      * If the app is the active device owner, but doesn't have work policy info, then we shouldn't
218      * have a Privacy entry for it.
219      */
testDeviceOwnerWithoutInfo()220     public void testDeviceOwnerWithoutInfo() throws Exception {
221         assertWithMessage("is device owner").that(mIsDeviceOwner).isTrue();
222 
223         disableWorkPolicyInfoActivity();
224 
225         launchPrivacySettingsAndAssertWorkPolicyInfoIsNotShowing();
226     }
227 
228     /**
229      * If the app is NOT the active device owner, then we should not have a Privacy entry for work
230      * policy info.
231      */
testNonDeviceOwnerWithInfo()232     public void testNonDeviceOwnerWithInfo() throws Exception {
233         assertWithMessage("is device owner").that(mIsDeviceOwner).isFalse();
234 
235         launchPrivacySettingsAndAssertWorkPolicyInfoIsNotShowing();
236     }
237 
238     /**
239      * If the app is NOT the active device owner, and doesn't have work policy info, then we should
240      * not have a Privacy entry for work policy info.
241      */
testNonDeviceOwnerWithoutInfo()242     public void testNonDeviceOwnerWithoutInfo() throws Exception {
243         assertWithMessage("is device owner").that(mIsDeviceOwner).isFalse();
244 
245         disableWorkPolicyInfoActivity();
246 
247         launchPrivacySettingsAndAssertWorkPolicyInfoIsNotShowing();
248     }
249 }
250