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