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.provider.Settings;
30 import android.server.wm.WindowManagerStateHelper;
31 import android.support.test.uiautomator.By;
32 import android.support.test.uiautomator.UiDevice;
33 import android.support.test.uiautomator.Until;
34 import android.test.InstrumentationTestCase;
35 import android.util.Log;
36 
37 import androidx.test.InstrumentationRegistry;
38 
39 import com.android.bedstead.dpmwrapper.DeviceOwnerHelper;
40 import com.android.bedstead.dpmwrapper.TestAppSystemServiceFactory;
41 import com.android.compatibility.common.util.enterprise.DeviceAdminReceiverUtils;
42 
43 /**
44  * Class for device-owner based tests.
45  *
46  * <p>This class handles making sure that the test is the device owner and that it has an active
47  * admin registered if necessary. The admin component can be accessed through {@link #getWho()}.
48  */
49 public final class DeviceOwnerTest extends InstrumentationTestCase {
50 
51     private static final String TAG = DeviceOwnerTest.class.getSimpleName();
52 
53     private static final String WORK_POLICY_INFO_TEXT = "Your work policy info";
54 
55     public static final int TIMEOUT_MS = 2_000;
56 
57     protected Context mContext;
58     protected UiDevice mDevice;
59 
60     /** Device Admin receiver for DO. */
61     public static final class BasicAdminReceiver extends DeviceAdminReceiver {
62 
63         @Override
onReceive(Context context, Intent intent)64         public void onReceive(Context context, Intent intent) {
65             // Ignore intents used by DpmWrapper IPC between current and system users
66             if (DeviceOwnerHelper.runManagerMethod(this, context, intent)) return;
67 
68             // Hack used to manually disable the admin during development
69             if (DeviceAdminReceiverUtils.disableSelf(context, intent)) return;
70 
71             super.onReceive(context, intent);
72         }
73     }
74 
75     static final String PACKAGE_NAME = DeviceOwnerTest.class.getPackage().getName();
76     static final ComponentName RECEIVER_COMPONENT =
77             new ComponentName(PACKAGE_NAME, BasicAdminReceiver.class.getName());
78 
79     protected DevicePolicyManager mDevicePolicyManager;
80     protected PackageManager mPackageManager;
81     protected boolean mIsDeviceOwner;
82 
83     @Override
setUp()84     protected void setUp() throws Exception {
85         super.setUp();
86         mContext = getInstrumentation().getContext();
87         mDevice = UiDevice.getInstance(getInstrumentation());
88         mPackageManager = mContext.getPackageManager();
89         mDevicePolicyManager = TestAppSystemServiceFactory.getDevicePolicyManager(mContext,
90                 BasicAdminReceiver.class);
91 
92         mIsDeviceOwner = mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME);
93         Log.d(TAG, "setup(): dpm=" + mDevicePolicyManager + ", isDO: " + mIsDeviceOwner);
94 
95         if (mIsDeviceOwner) {
96             assertWithMessage("isAdminActive(%s)", RECEIVER_COMPONENT)
97                     .that(mDevicePolicyManager.isAdminActive(RECEIVER_COMPONENT)).isTrue();
98 
99             // Note DPM.getDeviceOwner() now always returns null on non-DO users as of NYC.
100             assertWithMessage("%s.getDeviceOwner()", mDevicePolicyManager)
101                     .that(mDevicePolicyManager.getDeviceOwner()).isEqualTo(PACKAGE_NAME);
102         }
103 
104         try {
105             mDevice.setOrientationNatural();
106         } catch (RemoteException e) {
107             throw new RuntimeException("failed to freeze device orientation", e);
108         }
109         wakeupDeviceAndPressHome();
110     }
111 
wakeupDeviceAndPressHome()112     private void wakeupDeviceAndPressHome() throws Exception {
113         mDevice.wakeUp();
114         mDevice.pressMenu();
115         mDevice.pressHome();
116     }
117 
118     @Override
tearDown()119     protected void tearDown() throws Exception {
120         mDevice.pressBack();
121         mDevice.pressHome();
122         mDevice.waitForIdle(TIMEOUT_MS); // give UI time to finish animating
123     }
124 
launchPrivacyAndCheckWorkPolicyInfo()125     private boolean launchPrivacyAndCheckWorkPolicyInfo() throws Exception {
126         // Launch Settings
127         launchSettingsPage(InstrumentationRegistry.getContext(), Settings.ACTION_PRIVACY_SETTINGS);
128 
129         // Wait for loading permission usage data.
130         mDevice.waitForIdle(TIMEOUT_MS);
131 
132         Log.d(TAG, "Waiting " + TIMEOUT_MS + "ms for the '" + WORK_POLICY_INFO_TEXT + "' message");
133 
134         return (null != mDevice.wait(Until.findObject(By.text(WORK_POLICY_INFO_TEXT)), TIMEOUT_MS));
135     }
136 
launchSettingsPage(Context ctx, String pageName)137     private void launchSettingsPage(Context ctx, String pageName) throws Exception {
138         Intent intent = new Intent(pageName);
139         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
140 
141         ComponentName componentName =
142                 ctx.getPackageManager()
143                         .resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)
144                         .getComponentInfo()
145                         .getComponentName();
146         ctx.startActivity(intent);
147 
148         new WindowManagerStateHelper().waitForActivityState(componentName, STATE_RESUMED);
149     }
150 
disableWorkPolicyInfoActivity()151     private void disableWorkPolicyInfoActivity() {
152         mContext.getPackageManager()
153                 .setComponentEnabledSetting(
154                         new ComponentName(mContext, WorkPolicyInfoActivity.class),
155                         PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
156                         PackageManager.DONT_KILL_APP);
157     }
158 
launchPrivacySettingsAndAssertWorkPolicyInfoIsShowing()159     private void launchPrivacySettingsAndAssertWorkPolicyInfoIsShowing() throws Exception {
160         assertWithMessage("Work policy info (%s) on settings entry", WORK_POLICY_INFO_TEXT)
161                 .that(launchPrivacyAndCheckWorkPolicyInfo()).isTrue();
162     }
163 
launchPrivacySettingsAndAssertWorkPolicyInfoIsNotShowing()164     private void launchPrivacySettingsAndAssertWorkPolicyInfoIsNotShowing() throws Exception {
165         assertWithMessage("Work policy info (%s) on settings entry", WORK_POLICY_INFO_TEXT)
166                 .that(launchPrivacyAndCheckWorkPolicyInfo()).isFalse();
167     }
168 
169     /**
170      * If the app is the active device owner and has work policy info, then we should have a Privacy
171      * entry for it.
172      */
testDeviceOwnerWithInfo()173     public void testDeviceOwnerWithInfo() throws Exception {
174         assertWithMessage("is device owner").that(mIsDeviceOwner).isTrue();
175 
176         launchPrivacySettingsAndAssertWorkPolicyInfoIsShowing();
177     }
178 
179     /**
180      * If the app is the active device owner, but doesn't have work policy info, then we shouldn't
181      * have a Privacy entry for it.
182      */
testDeviceOwnerWithoutInfo()183     public void testDeviceOwnerWithoutInfo() throws Exception {
184         assertWithMessage("is device owner").that(mIsDeviceOwner).isTrue();
185 
186         disableWorkPolicyInfoActivity();
187 
188         launchPrivacySettingsAndAssertWorkPolicyInfoIsNotShowing();
189     }
190 
191     /**
192      * If the app is NOT the active device owner, then we should not have a Privacy entry for work
193      * policy info.
194      */
testNonDeviceOwnerWithInfo()195     public void testNonDeviceOwnerWithInfo() throws Exception {
196         assertWithMessage("is device owner").that(mIsDeviceOwner).isFalse();
197 
198         launchPrivacySettingsAndAssertWorkPolicyInfoIsNotShowing();
199     }
200 
201     /**
202      * If the app is NOT the active device owner, and doesn't have work policy info, then we should
203      * not have a Privacy entry for work policy info.
204      */
testNonDeviceOwnerWithoutInfo()205     public void testNonDeviceOwnerWithoutInfo() throws Exception {
206         assertWithMessage("is device owner").that(mIsDeviceOwner).isFalse();
207 
208         disableWorkPolicyInfoActivity();
209 
210         launchPrivacySettingsAndAssertWorkPolicyInfoIsNotShowing();
211     }
212 }
213