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