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