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