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 adapter.add(createSetLockTaskFeaturesTest( 175 TEST_ID_KEYGUARD, 176 LOCK_TASK_FEATURE_KEYGUARD, 177 R.string.device_owner_lock_task_ui_keyguard_test, 178 R.string.device_owner_lock_task_ui_keyguard_test_info)); 179 } 180 181 final Intent stopLockTaskIntent = new Intent(this, LockTaskUiTestActivity.class); 182 stopLockTaskIntent.setAction(ACTION_STOP_LOCK_TASK); 183 adapter.add(createInteractiveTestItem(this, 184 TEST_ID_STOP_LOCK_TASK, 185 R.string.device_owner_lock_task_ui_stop_lock_task_test, 186 R.string.device_owner_lock_task_ui_stop_lock_task_test_info, 187 new ButtonInfo( 188 R.string.device_owner_lock_task_ui_stop_lock_task_test, 189 stopLockTaskIntent 190 ))); 191 } 192 193 /** Receives LockTask start/stop callbacks forwarded by {@link DeviceAdminTestReceiver}. */ 194 private final class LockTaskStateChangedReceiver extends BroadcastReceiver { 195 @Override onReceive(Context context, Intent intent)196 public void onReceive(Context context, Intent intent) { 197 String action = intent.getAction(); 198 switch (action) { 199 case ACTION_LOCK_TASK_STARTED: 200 if (mLockTaskStartedLatch != null) { 201 mLockTaskStartedLatch.countDown(); 202 } 203 break; 204 case ACTION_LOCK_TASK_STOPPED: 205 if (mLockTaskStoppedLatch != null) { 206 mLockTaskStoppedLatch.countDown(); 207 } 208 break; 209 } 210 } 211 } 212 213 @Override onResume()214 protected void onResume() { 215 super.onResume(); 216 mStateChangedReceiver = new LockTaskStateChangedReceiver(); 217 final IntentFilter filter = new IntentFilter(); 218 filter.addAction(ACTION_LOCK_TASK_STARTED); 219 filter.addAction(ACTION_LOCK_TASK_STOPPED); 220 LocalBroadcastManager.getInstance(this).registerReceiver(mStateChangedReceiver, filter); 221 } 222 223 @Override onPause()224 protected void onPause() { 225 if (mStateChangedReceiver != null) { 226 LocalBroadcastManager.getInstance(this).unregisterReceiver(mStateChangedReceiver); 227 mStateChangedReceiver = null; 228 } 229 super.onPause(); 230 } 231 232 /** 233 * Starts LockTask mode and waits for callback from {@link DeviceAdminTestReceiver} to confirm 234 * LockTask has started successfully. If the callback isn't received, the entire test will be 235 * marked as failed. 236 * 237 * @see LockTaskStateChangedReceiver 238 */ startLockTaskMode()239 private void startLockTaskMode() { 240 if (mAm.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_LOCKED) { 241 return; 242 } 243 244 mLockTaskStartedLatch = new CountDownLatch(1); 245 try { 246 mDpm.setLockTaskPackages(ADMIN_RECEIVER, new String[] {TEST_PACKAGE_NAME}); 247 mDpm.setLockTaskFeatures(ADMIN_RECEIVER, LOCK_TASK_FEATURE_NONE); 248 startLockTask(); 249 250 new CheckLockTaskStateTask() { 251 @Override 252 protected void onPostExecute(Boolean success) { 253 if (success) { 254 issueTestNotification(); 255 } else { 256 notifyFailure(getTestId(), "Failed to start LockTask mode"); 257 } 258 } 259 }.execute(mLockTaskStartedLatch); 260 } catch (SecurityException e) { 261 Log.e(TAG, e.getMessage(), e); 262 Toast.makeText(this, "Failed to run test. Did you set up device owner correctly?", 263 Toast.LENGTH_SHORT).show(); 264 } 265 } 266 267 /** 268 * Stops LockTask mode and waits for callback from {@link DeviceAdminTestReceiver} to confirm 269 * LockTask has stopped successfully. If the callback isn't received, the "Stop LockTask mode" 270 * test case will be marked as failed. 271 * 272 * Note that we {@link #finish()} this activity here, since it's started by the "Stop LockTask 273 * mode" test activity, and shouldn't be exposed to the tester once its job is done. 274 * 275 * @see LockTaskStateChangedReceiver 276 */ stopLockTaskMode()277 private void stopLockTaskMode() { 278 if (mAm.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_NONE) { 279 finish(); 280 return; 281 } 282 283 mLockTaskStoppedLatch = new CountDownLatch(1); 284 try { 285 stopLockTask(); 286 287 new CheckLockTaskStateTask() { 288 @Override 289 protected void onPostExecute(Boolean success) { 290 if (!success) { 291 notifyFailure(TEST_ID_STOP_LOCK_TASK, "Failed to stop LockTask mode"); 292 } 293 cancelTestNotification(); 294 mDpm.setLockTaskFeatures(ADMIN_RECEIVER, LOCK_TASK_FEATURE_NONE); 295 mDpm.setLockTaskPackages(ADMIN_RECEIVER, new String[] {}); 296 LockTaskUiTestActivity.this.finish(); 297 } 298 }.execute(mLockTaskStoppedLatch); 299 } catch (SecurityException e) { 300 Log.e(TAG, e.getMessage(), e); 301 Toast.makeText(this, "Failed to finish test. Did you set up device owner correctly?", 302 Toast.LENGTH_SHORT).show(); 303 } 304 } 305 306 private abstract class CheckLockTaskStateTask extends AsyncTask<CountDownLatch, Void, Boolean> { 307 @Override doInBackground(CountDownLatch... latches)308 protected Boolean doInBackground(CountDownLatch... latches) { 309 if (latches.length > 0 && latches[0] != null) { 310 try { 311 return latches[0].await(1, TimeUnit.SECONDS); 312 } catch (InterruptedException e) { 313 // Fall through 314 } 315 } 316 return false; 317 } 318 319 @Override onPostExecute(Boolean success)320 protected abstract void onPostExecute(Boolean success); 321 } 322 notifyFailure(String testId, String message)323 private void notifyFailure(String testId, String message) { 324 Log.e(TAG, message); 325 Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); 326 TestResult.setFailedResult(this, testId, message); 327 } 328 issueTestNotification()329 private void issueTestNotification() { 330 String channelId = getTestId(); 331 if (mNotifyMgr.getNotificationChannel(channelId) == null) { 332 NotificationChannel channel = new NotificationChannel( 333 channelId, getTestId(), NotificationManager.IMPORTANCE_HIGH); 334 mNotifyMgr.createNotificationChannel(channel); 335 } 336 337 Notification note = new Notification.Builder(this, channelId) 338 .setContentTitle(getString(R.string.device_owner_lock_task_ui_test)) 339 .setSmallIcon(android.R.drawable.sym_def_app_icon) 340 .setOngoing(true) 341 .build(); 342 343 mNotifyMgr.notify(0, note); 344 } 345 cancelTestNotification()346 private void cancelTestNotification() { 347 mNotifyMgr.cancelAll(); 348 } 349 createSetLockTaskFeaturesTest(String testId, int featureFlags, int titleResId, int detailResId)350 private TestListItem createSetLockTaskFeaturesTest(String testId, int featureFlags, 351 int titleResId, int detailResId) { 352 final Intent commandIntent = new Intent(CommandReceiverActivity.ACTION_EXECUTE_COMMAND); 353 commandIntent.putExtra(CommandReceiverActivity.EXTRA_COMMAND, 354 CommandReceiverActivity.COMMAND_SET_LOCK_TASK_FEATURES); 355 commandIntent.putExtra(CommandReceiverActivity.EXTRA_VALUE, featureFlags); 356 357 return createInteractiveTestItem(this, testId, titleResId, detailResId, 358 new ButtonInfo(titleResId, commandIntent)); 359 } 360 361 @Override getTestId()362 public String getTestId() { 363 return getIntent().getStringExtra(EXTRA_TEST_ID); 364 } 365 } 366