1/* 2 * Copyright (C) 2018 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 17package com.android.server.appops; 18 19import static com.google.common.truth.Truth.assertThat; 20 21import static org.junit.Assert.assertFalse; 22import static org.junit.Assert.assertTrue; 23import static org.mockito.Mockito.eq; 24import static org.mockito.Mockito.mock; 25import static org.mockito.Mockito.reset; 26import static org.mockito.Mockito.timeout; 27import static org.mockito.Mockito.verify; 28import static org.mockito.Mockito.verifyNoMoreInteractions; 29 30import android.app.AppOpsManager; 31import android.app.AppOpsManager.OnOpActiveChangedListener; 32import android.content.Context; 33import android.os.Process; 34import android.support.test.InstrumentationRegistry; 35import android.support.test.filters.SmallTest; 36import android.support.test.runner.AndroidJUnit4; 37 38import org.junit.Test; 39import org.junit.runner.RunWith; 40 41import java.util.List; 42 43/** 44 * Tests app ops version upgrades 45 */ 46@SmallTest 47@RunWith(AndroidJUnit4.class) 48public class AppOpsActiveWatcherTest { 49 50 private static final long NOTIFICATION_TIMEOUT_MILLIS = 5000; 51 52 @Test 53 public void testWatchActiveOps() { 54 // Create a mock listener 55 final OnOpActiveChangedListener listener = mock(OnOpActiveChangedListener.class); 56 57 // Start watching active ops 58 final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); 59 appOpsManager.startWatchingActive(new int[] {AppOpsManager.OP_CAMERA, 60 AppOpsManager.OP_RECORD_AUDIO}, listener); 61 62 // Start the op 63 appOpsManager.startOp(AppOpsManager.OP_CAMERA); 64 65 // Verify that we got called for the op being active 66 verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS) 67 .times(1)).onOpActiveChanged(eq(AppOpsManager.OP_CAMERA), 68 eq(Process.myUid()), eq(getContext().getPackageName()), eq(true)); 69 70 // This should be the only callback we got 71 verifyNoMoreInteractions(listener); 72 73 // Start with a clean slate 74 reset(listener); 75 76 // Verify that the op is active 77 assertThat(appOpsManager.isOperationActive(AppOpsManager.OP_CAMERA, 78 Process.myUid(), getContext().getPackageName())).isTrue(); 79 80 // Finish the op 81 appOpsManager.finishOp(AppOpsManager.OP_CAMERA); 82 83 // Verify that we got called for the op being active 84 verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS) 85 .times(1)).onOpActiveChanged(eq(AppOpsManager.OP_CAMERA), 86 eq(Process.myUid()), eq(getContext().getPackageName()), eq(false)); 87 88 // Verify that the op is not active 89 assertThat(appOpsManager.isOperationActive(AppOpsManager.OP_CAMERA, 90 Process.myUid(), getContext().getPackageName())).isFalse(); 91 92 // This should be the only callback we got 93 verifyNoMoreInteractions(listener); 94 95 // Start with a clean slate 96 reset(listener); 97 98 // Stop watching active ops 99 appOpsManager.stopWatchingActive(listener); 100 101 // Start the op 102 appOpsManager.startOp(AppOpsManager.OP_CAMERA); 103 104 // We should not be getting any callbacks 105 verifyNoMoreInteractions(listener); 106 107 // Finish the op 108 appOpsManager.finishOp(AppOpsManager.OP_CAMERA); 109 110 // We should not be getting any callbacks 111 verifyNoMoreInteractions(listener); 112 } 113 114 @Test 115 public void testIsRunning() throws Exception { 116 final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); 117 // Start the op 118 appOpsManager.startOp(AppOpsManager.OP_CAMERA); 119 120 assertTrue("Camera should be running", isCameraOn(appOpsManager)); 121 122 // Finish the op 123 appOpsManager.finishOp(AppOpsManager.OP_CAMERA); 124 125 assertFalse("Camera should not be running", isCameraOn(appOpsManager)); 126 } 127 128 private boolean isCameraOn(AppOpsManager appOpsManager) { 129 List<AppOpsManager.PackageOps> packages 130 = appOpsManager.getPackagesForOps(new int[] {AppOpsManager.OP_CAMERA}); 131 // AppOpsManager can return null when there is no requested data. 132 if (packages != null) { 133 final int numPackages = packages.size(); 134 for (int packageInd = 0; packageInd < numPackages; packageInd++) { 135 AppOpsManager.PackageOps packageOp = packages.get(packageInd); 136 List<AppOpsManager.OpEntry> opEntries = packageOp.getOps(); 137 if (opEntries != null) { 138 final int numOps = opEntries.size(); 139 for (int opInd = 0; opInd < numOps; opInd++) { 140 AppOpsManager.OpEntry opEntry = opEntries.get(opInd); 141 if (opEntry.getOp() == AppOpsManager.OP_CAMERA) { 142 if (opEntry.isRunning()) { 143 return true; 144 } 145 } 146 } 147 } 148 } 149 } 150 151 return false; 152 } 153 154 private static Context getContext() { 155 return InstrumentationRegistry.getContext(); 156 } 157}