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.cts.verifier.managedprovisioning;
18 
19 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
20 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME;
21 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD;
22 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
23 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
24 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
25 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO;
26 
27 import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
28 
29 import android.app.ActivityManager;
30 import android.app.Notification;
31 import android.app.NotificationChannel;
32 import android.app.NotificationManager;
33 import android.app.admin.DevicePolicyManager;
34 import android.content.BroadcastReceiver;
35 import android.content.ComponentName;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.content.IntentFilter;
39 import android.content.pm.PackageManager;
40 import android.database.DataSetObserver;
41 import android.os.AsyncTask;
42 import android.os.Bundle;
43 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
44 import android.util.Log;
45 import android.widget.Button;
46 import android.widget.Toast;
47 
48 import com.android.cts.verifier.ArrayTestListAdapter;
49 import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
50 import com.android.cts.verifier.PassFailButtons;
51 import com.android.cts.verifier.R;
52 import com.android.cts.verifier.TestListAdapter.TestListItem;
53 import com.android.cts.verifier.TestResult;
54 
55 import java.util.concurrent.CountDownLatch;
56 import java.util.concurrent.TimeUnit;
57 
58 /**
59  * Tests for {@link DevicePolicyManager#setLockTaskFeatures(ComponentName, int)}.
60  */
61 public class LockTaskUiTestActivity extends PassFailButtons.TestListActivity {
62 
63     private static final String TAG = LockTaskUiTestActivity.class.getSimpleName();
64 
65     public static final String EXTRA_TEST_ID =
66             "com.android.cts.verifier.managedprovisioning.extra.TEST_ID";
67 
68     /** Broadcast action sent by {@link DeviceAdminTestReceiver} when LockTask starts. */
69     static final String ACTION_LOCK_TASK_STARTED =
70             "com.android.cts.verifier.managedprovisioning.action.LOCK_TASK_STARTED";
71     /** Broadcast action sent by {@link DeviceAdminTestReceiver} when LockTask stops. */
72     static final String ACTION_LOCK_TASK_STOPPED =
73             "com.android.cts.verifier.managedprovisioning.action.LOCK_TASK_STOPPED";
74 
75     private static final ComponentName ADMIN_RECEIVER =
76             DeviceAdminTestReceiver.getReceiverComponentName();
77     private static final String TEST_PACKAGE_NAME = "com.android.cts.verifier";
78     private static final String ACTION_STOP_LOCK_TASK =
79             "com.android.cts.verifier.managedprovisioning.action.STOP_LOCK_TASK";
80 
81     private static final String TEST_ID_DEFAULT = "lock-task-ui-default";
82     private static final String TEST_ID_SYSTEM_INFO = "lock-task-ui-system-info";
83     private static final String TEST_ID_NOTIFICATIONS = "lock-task-ui-notifications";
84     private static final String TEST_ID_HOME = "lock-task-ui-home";
85     private static final String TEST_ID_RECENTS = "lock-task-ui-recents";
86     private static final String TEST_ID_GLOBAL_ACTIONS = "lock-task-ui-global-actions";
87     private static final String TEST_ID_KEYGUARD = "lock-task-ui-keyguard";
88     private static final String TEST_ID_STOP_LOCK_TASK = "lock-task-ui-stop-lock-task";
89 
90     private DevicePolicyManager mDpm;
91     private ActivityManager mAm;
92     private NotificationManager mNotifyMgr;
93 
94     private LockTaskStateChangedReceiver mStateChangedReceiver;
95     private CountDownLatch mLockTaskStartedLatch;
96     private CountDownLatch mLockTaskStoppedLatch;
97 
98     @Override
onCreate(Bundle savedInstanceState)99     protected void onCreate(Bundle savedInstanceState) {
100         super.onCreate(savedInstanceState);
101         setContentView(R.layout.device_owner_lock_task_ui);
102         setPassFailButtonClickListeners();
103 
104         mDpm = getSystemService(DevicePolicyManager.class);
105         mAm = getSystemService(ActivityManager.class);
106         mNotifyMgr = getSystemService(NotificationManager.class);
107 
108         final ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
109         addTestsToAdapter(adapter);
110         adapter.registerDataSetObserver(new DataSetObserver() {
111             @Override
112             public void onChanged() {
113                 updatePassButton();
114             }
115         });
116         setTestListAdapter(adapter);
117 
118         Button startLockTaskButton = findViewById(R.id.start_lock_task_button);
119         startLockTaskButton.setOnClickListener((view) -> startLockTaskMode());
120 
121         if (ACTION_STOP_LOCK_TASK.equals(getIntent().getAction())) {
122             // This means we're started by the "stop LockTask mode" test activity (the last one in
123             // the list) in order to stop LockTask.
124             stopLockTaskMode();
125         }
126     }
127 
addTestsToAdapter(final ArrayTestListAdapter adapter)128     private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
129         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
130             adapter.add(createSetLockTaskFeaturesTest(
131                     TEST_ID_DEFAULT,
132                     LOCK_TASK_FEATURE_NONE,
133                     R.string.device_owner_lock_task_ui_default_test,
134                     R.string.device_owner_lock_task_ui_default_test_info));
135 
136             adapter.add(createSetLockTaskFeaturesTest(
137                     TEST_ID_SYSTEM_INFO,
138                     LOCK_TASK_FEATURE_SYSTEM_INFO,
139                     R.string.device_owner_lock_task_ui_system_info_test,
140                     R.string.device_owner_lock_task_ui_system_info_test_info));
141         }
142 
143         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
144             adapter.add(createSetLockTaskFeaturesTest(
145                     TEST_ID_NOTIFICATIONS,
146                     LOCK_TASK_FEATURE_HOME | LOCK_TASK_FEATURE_NOTIFICATIONS,
147                     R.string.device_owner_lock_task_ui_notifications_test,
148                     R.string.device_owner_lock_task_ui_notifications_test_info));
149         }
150 
151         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
152             adapter.add(createSetLockTaskFeaturesTest(
153                     TEST_ID_HOME,
154                     LOCK_TASK_FEATURE_HOME,
155                     R.string.device_owner_lock_task_ui_home_test,
156                     R.string.device_owner_lock_task_ui_home_test_info));
157         }
158 
159         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
160             adapter.add(createSetLockTaskFeaturesTest(
161                     TEST_ID_RECENTS,
162                     LOCK_TASK_FEATURE_HOME | LOCK_TASK_FEATURE_OVERVIEW,
163                     R.string.device_owner_lock_task_ui_recents_test,
164                     R.string.device_owner_lock_task_ui_recents_test_info));
165         }
166 
167         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
168             adapter.add(createSetLockTaskFeaturesTest(
169                     TEST_ID_GLOBAL_ACTIONS,
170                     LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
171                     R.string.device_owner_lock_task_ui_global_actions_test,
172                     R.string.device_owner_lock_task_ui_global_actions_test_info));
173         }
174 
175         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
176                 && getPackageManager().hasSystemFeature(
177                 PackageManager.FEATURE_SECURE_LOCK_SCREEN)) {
178             adapter.add(createSetLockTaskFeaturesTest(
179                     TEST_ID_KEYGUARD,
180                     LOCK_TASK_FEATURE_KEYGUARD,
181                     R.string.device_owner_lock_task_ui_keyguard_test,
182                     R.string.device_owner_lock_task_ui_keyguard_test_info));
183         }
184 
185         final Intent stopLockTaskIntent = new Intent(this, LockTaskUiTestActivity.class);
186         stopLockTaskIntent.setAction(ACTION_STOP_LOCK_TASK);
187         adapter.add(createInteractiveTestItem(this,
188                 TEST_ID_STOP_LOCK_TASK,
189                 R.string.device_owner_lock_task_ui_stop_lock_task_test,
190                 R.string.device_owner_lock_task_ui_stop_lock_task_test_info,
191                 new ButtonInfo(
192                         R.string.device_owner_lock_task_ui_stop_lock_task_test,
193                         stopLockTaskIntent
194                 )));
195     }
196 
197     /** Receives LockTask start/stop callbacks forwarded by {@link DeviceAdminTestReceiver}. */
198     private final class LockTaskStateChangedReceiver extends BroadcastReceiver {
199         @Override
onReceive(Context context, Intent intent)200         public void onReceive(Context context, Intent intent) {
201             String action = intent.getAction();
202             switch (action) {
203                 case ACTION_LOCK_TASK_STARTED:
204                     if (mLockTaskStartedLatch != null) {
205                         mLockTaskStartedLatch.countDown();
206                     }
207                     break;
208                 case ACTION_LOCK_TASK_STOPPED:
209                     if (mLockTaskStoppedLatch != null) {
210                         mLockTaskStoppedLatch.countDown();
211                     }
212                     break;
213             }
214         }
215     }
216 
217     @Override
onResume()218     protected void onResume() {
219         super.onResume();
220         mStateChangedReceiver = new LockTaskStateChangedReceiver();
221         final IntentFilter filter = new IntentFilter();
222         filter.addAction(ACTION_LOCK_TASK_STARTED);
223         filter.addAction(ACTION_LOCK_TASK_STOPPED);
224         LocalBroadcastManager.getInstance(this).registerReceiver(mStateChangedReceiver, filter);
225     }
226 
227     @Override
onPause()228     protected void onPause() {
229         if (mStateChangedReceiver != null) {
230             LocalBroadcastManager.getInstance(this).unregisterReceiver(mStateChangedReceiver);
231             mStateChangedReceiver = null;
232         }
233         super.onPause();
234     }
235 
236     /**
237      * Starts LockTask mode and waits for callback from {@link DeviceAdminTestReceiver} to confirm
238      * LockTask has started successfully. If the callback isn't received, the entire test will be
239      * marked as failed.
240      *
241      * @see LockTaskStateChangedReceiver
242      */
startLockTaskMode()243     private void startLockTaskMode() {
244         if (mAm.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_LOCKED) {
245             return;
246         }
247 
248         mLockTaskStartedLatch = new CountDownLatch(1);
249         try {
250             mDpm.setLockTaskPackages(ADMIN_RECEIVER, new String[] {TEST_PACKAGE_NAME});
251             mDpm.setLockTaskFeatures(ADMIN_RECEIVER, LOCK_TASK_FEATURE_NONE);
252             startLockTask();
253 
254             new CheckLockTaskStateTask() {
255                 @Override
256                 protected void onPostExecute(Boolean success) {
257                     if (success) {
258                         issueTestNotification();
259                     } else {
260                         notifyFailure(getTestId(), "Failed to start LockTask mode");
261                     }
262                 }
263             }.execute(mLockTaskStartedLatch);
264         } catch (SecurityException e) {
265             Log.e(TAG, e.getMessage(), e);
266             Toast.makeText(this, "Failed to run test. Did you set up device owner correctly?",
267                     Toast.LENGTH_SHORT).show();
268         }
269     }
270 
271     /**
272      * Stops LockTask mode and waits for callback from {@link DeviceAdminTestReceiver} to confirm
273      * LockTask has stopped successfully. If the callback isn't received, the "Stop LockTask mode"
274      * test case will be marked as failed.
275      *
276      * Note that we {@link #finish()} this activity here, since it's started by the "Stop LockTask
277      * mode" test activity, and shouldn't be exposed to the tester once its job is done.
278      *
279      * @see LockTaskStateChangedReceiver
280      */
stopLockTaskMode()281     private void stopLockTaskMode() {
282         if (mAm.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_NONE) {
283             finish();
284             return;
285         }
286 
287         mLockTaskStoppedLatch = new CountDownLatch(1);
288         try {
289             stopLockTask();
290 
291             new CheckLockTaskStateTask() {
292                 @Override
293                 protected void onPostExecute(Boolean success) {
294                     if (!success) {
295                         notifyFailure(TEST_ID_STOP_LOCK_TASK, "Failed to stop LockTask mode");
296                     }
297                     cancelTestNotification();
298                     mDpm.setLockTaskFeatures(ADMIN_RECEIVER, LOCK_TASK_FEATURE_NONE);
299                     mDpm.setLockTaskPackages(ADMIN_RECEIVER, new String[] {});
300                     LockTaskUiTestActivity.this.finish();
301                 }
302             }.execute(mLockTaskStoppedLatch);
303         } catch (SecurityException e) {
304             Log.e(TAG, e.getMessage(), e);
305             Toast.makeText(this, "Failed to finish test. Did you set up device owner correctly?",
306                     Toast.LENGTH_SHORT).show();
307         }
308     }
309 
310     private abstract class CheckLockTaskStateTask extends AsyncTask<CountDownLatch, Void, Boolean> {
311         @Override
doInBackground(CountDownLatch... latches)312         protected Boolean doInBackground(CountDownLatch... latches) {
313             if (latches.length > 0 && latches[0] != null) {
314                 try {
315                     return latches[0].await(1, TimeUnit.SECONDS);
316                 } catch (InterruptedException e) {
317                     // Fall through
318                 }
319             }
320             return false;
321         }
322 
323         @Override
onPostExecute(Boolean success)324         protected abstract void onPostExecute(Boolean success);
325     }
326 
notifyFailure(String testId, String message)327     private void notifyFailure(String testId, String message) {
328         Log.e(TAG, message);
329         Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
330         TestResult.setFailedResult(this, testId, message);
331     }
332 
issueTestNotification()333     private void issueTestNotification() {
334         String channelId = getTestId();
335         if (mNotifyMgr.getNotificationChannel(channelId) == null) {
336             NotificationChannel channel = new NotificationChannel(
337                     channelId, getTestId(), NotificationManager.IMPORTANCE_HIGH);
338             mNotifyMgr.createNotificationChannel(channel);
339         }
340 
341         Notification note = new Notification.Builder(this, channelId)
342                 .setContentTitle(getString(R.string.device_owner_lock_task_ui_test))
343                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
344                 .setOngoing(true)
345                 .extend(new Notification.TvExtender())
346                 .build();
347 
348         mNotifyMgr.notify(0, note);
349     }
350 
cancelTestNotification()351     private void cancelTestNotification() {
352         mNotifyMgr.cancelAll();
353     }
354 
createSetLockTaskFeaturesTest(String testId, int featureFlags, int titleResId, int detailResId)355     private TestListItem createSetLockTaskFeaturesTest(String testId, int featureFlags,
356             int titleResId, int detailResId) {
357         final Intent commandIntent = new Intent(CommandReceiverActivity.ACTION_EXECUTE_COMMAND);
358         commandIntent.putExtra(CommandReceiverActivity.EXTRA_COMMAND,
359                 CommandReceiverActivity.COMMAND_SET_LOCK_TASK_FEATURES);
360         commandIntent.putExtra(CommandReceiverActivity.EXTRA_VALUE, featureFlags);
361 
362         return createInteractiveTestItem(this, testId, titleResId, detailResId,
363                 new ButtonInfo(titleResId, commandIntent));
364     }
365 
366     @Override
getTestId()367     public String getTestId() {
368         return getIntent().getStringExtra(EXTRA_TEST_ID);
369     }
370 }
371