1 /* 2 * Copyright (C) 2021 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 package com.android.cts.devicepolicy; 17 18 import static android.app.admin.DevicePolicyManager.operationToString; 19 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.util.Log; 25 26 import com.android.bedstead.dpmwrapper.TestAppHelper; 27 28 import junit.framework.AssertionFailedError; 29 30 import java.util.concurrent.LinkedBlockingQueue; 31 import java.util.concurrent.TimeUnit; 32 33 //TODO(b/174859111): move to automotive-only section 34 /** 35 * Helper class used by test apps to get the safety event received by the device owner's 36 * {@link android.app.admin.DeviceAdminReceiver}. 37 */ 38 public final class OperationSafetyChangedCallback { 39 40 private static final String TAG = OperationSafetyChangedCallback.class.getSimpleName(); 41 42 private static final String ACTION_STATE_CHANGED = "operation_safety_state_changed"; 43 private static final String EXTRA_REASON = "reason"; 44 private static final String EXTRA_IS_SAFE = "is_safe"; 45 46 private static final long TIMEOUT_MS = 50_000; 47 48 private final LinkedBlockingQueue<OperationSafetyChangedEvent> mEvents = 49 new LinkedBlockingQueue<>(); 50 51 private final boolean mForDeviceOwner; 52 53 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 54 @Override 55 public void onReceive(Context context, Intent intent) { 56 String action = intent.getAction(); 57 Log.v(TAG, "onReceive(): " + intent); 58 if (!ACTION_STATE_CHANGED.equals(action)) { 59 Log.e(TAG, "Invalid action " + action + " on intent " + intent); 60 return; 61 } 62 if (!intent.hasExtra(EXTRA_REASON)) { 63 Log.e(TAG, "No " + EXTRA_REASON + " extra on intent " + intent); 64 return; 65 } 66 if (!intent.hasExtra(EXTRA_IS_SAFE)) { 67 Log.e(TAG, "No " + EXTRA_IS_SAFE + " extra on intent " + intent); 68 return; 69 } 70 OperationSafetyChangedEvent event = new OperationSafetyChangedEvent( 71 intent.getIntExtra(EXTRA_REASON, 42), 72 intent.getBooleanExtra(EXTRA_IS_SAFE, false)); 73 Log.d(TAG, "Received intent with event " + event + " on user " + context.getUserId()); 74 mEvents.offer(event); 75 } 76 }; 77 OperationSafetyChangedCallback(boolean forDeviceOwner)78 private OperationSafetyChangedCallback(boolean forDeviceOwner) { 79 mForDeviceOwner = forDeviceOwner; 80 } 81 82 /** 83 * Creates and registers a callback in the given context. 84 */ register(Context context, boolean forDeviceOwner)85 public static OperationSafetyChangedCallback register(Context context, boolean forDeviceOwner) { 86 Log.d(TAG, "Registering " + ACTION_STATE_CHANGED + " on user " + context.getUserId()); 87 OperationSafetyChangedCallback callback = new OperationSafetyChangedCallback( 88 forDeviceOwner); 89 TestAppHelper.registerTestCaseReceiver(context, callback.mReceiver, 90 new IntentFilter(ACTION_STATE_CHANGED), forDeviceOwner); 91 return callback; 92 } 93 94 /** 95 * Unregister this callback in the given context. 96 */ unregister(Context context)97 public void unregister(Context context) { 98 Log.d(TAG, "Unregistering " + mReceiver + " on user " + context.getUserId()); 99 TestAppHelper.unregisterTestCaseReceiver(context, mReceiver, mForDeviceOwner); 100 } 101 102 /** 103 * Gets the intent for the given event. 104 */ intentFor(OperationSafetyChangedEvent event)105 public static Intent intentFor(OperationSafetyChangedEvent event) { 106 return new Intent(ACTION_STATE_CHANGED) 107 .putExtra(EXTRA_REASON, event.reason) 108 .putExtra(EXTRA_IS_SAFE, event.isSafe); 109 } 110 111 /** 112 * Gets next event or fail. 113 */ getNextEvent(int operation)114 public OperationSafetyChangedEvent getNextEvent(int operation) { 115 OperationSafetyChangedEvent event = null; 116 try { 117 event = mEvents.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS); 118 } catch (InterruptedException e) { 119 String msg = "interrupted waiting for event"; 120 Log.e(TAG, msg, e); 121 Thread.currentThread().interrupt(); 122 throw new AssertionFailedError(msg); 123 } 124 if (event == null) { 125 String msg = "didn't receive an OperationSafetyChangedEvent for " 126 + operationToString(operation) + " in " + TIMEOUT_MS + "ms on " + this; 127 Log.e(TAG, msg); 128 throw new AssertionFailedError(msg); 129 } 130 return event; 131 } 132 133 @Override toString()134 public String toString() { 135 return "OperationSafetyChangedCallback[events=" + mEvents + "]"; 136 } 137 } 138