1 /*
2  * Copyright (C) 2014 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 android.permission.cts;
18 
19 import static com.android.ex.camera2.blocking.BlockingStateCallback.*;
20 
21 import android.content.Context;
22 import android.hardware.camera2.CameraCharacteristics;
23 import android.hardware.camera2.CameraCharacteristics.Key;
24 import android.hardware.camera2.CameraDevice;
25 import android.hardware.camera2.CameraManager;
26 import android.os.Handler;
27 import android.os.HandlerThread;
28 import android.platform.test.annotations.Presubmit;
29 import android.test.AndroidTestCase;
30 import android.util.Log;
31 
32 import com.android.ex.camera2.blocking.BlockingCameraManager;
33 import com.android.ex.camera2.blocking.BlockingStateCallback;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 
38 /**
39  * Tests for Camera2 API related Permissions. Currently, this means
40  * android.permission.CAMERA.
41  */
42 public class Camera2PermissionTest extends AndroidTestCase {
43     private static final String TAG = "Camera2PermissionTest";
44     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
45     private static final int CAMERA_CLOSE_TIMEOUT_MS = 2000;
46 
47     private CameraManager mCameraManager;
48     private CameraDevice mCamera;
49     private BlockingStateCallback mCameraListener;
50     private String[] mCameraIds;
51     protected Handler mHandler;
52     protected HandlerThread mHandlerThread;
53 
54     @Override
setContext(Context context)55     public void setContext(Context context) {
56         super.setContext(context);
57         mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
58         assertNotNull("Can't connect to camera manager!", mCameraManager);
59     }
60 
61     /**
62      * Set up the camera2 test case required environments, including CameraManager,
63      * HandlerThread, Camera IDs, and CameraStateCallback etc.
64      */
65     @Override
setUp()66     protected void setUp() throws Exception {
67         super.setUp();
68         mCameraIds = mCameraManager.getCameraIdList();
69         assertNotNull("Camera ids shouldn't be null", mCameraIds);
70         mHandlerThread = new HandlerThread(TAG);
71         mHandlerThread.start();
72         mHandler = new Handler(mHandlerThread.getLooper());
73         mCameraListener = new BlockingStateCallback();
74     }
75 
76     @Override
tearDown()77     protected void tearDown() throws Exception {
78         mHandlerThread.quitSafely();
79         mHandler = null;
80 
81         super.tearDown();
82     }
83 
84     /**
85      * Attempt to open camera. Requires Permission:
86      * {@link android.Manifest.permission#CAMERA}.
87      */
testCameraOpen()88     public void testCameraOpen() throws Exception {
89         for (String id : mCameraIds) {
90             try {
91                 openCamera(id);
92                 fail("Was able to open camera " + id + " with no permission");
93             }
94             catch (SecurityException e) {
95                 // expected
96             } finally {
97                 closeCamera();
98             }
99         }
100     }
101 
102     /**
103      * Check that no system cameras can be discovered without
104      * {@link android.Manifest.permission#CAMERA} and android.permission.SYSTEM_CAMERA
105      */
testSystemCameraDiscovery()106     public void testSystemCameraDiscovery() throws Exception {
107         for (String id : mCameraIds) {
108             Log.i(TAG, "testSystemCameraDiscovery for camera id " +  id);
109             CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
110             assertNotNull("Camera characteristics shouldn't be null", characteristics);
111             int[] availableCapabilities =
112                     characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
113             assertTrue("Camera capabilities shouldn't be null", availableCapabilities != null);
114             List<Integer> capList = toList(availableCapabilities);
115             assertFalse("System camera device " + id + " should not be public",
116                     capList.contains(
117                             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA));
118         }
119     }
120 
121     /**
122      * Check the absence of camera characteristics keys that require Permission:
123      * {@link android.Manifest.permission#CAMERA}.
124      */
testCameraCharacteristicsNeedingPermission()125     public void testCameraCharacteristicsNeedingPermission() throws Exception {
126         for (String id : mCameraIds) {
127             CameraCharacteristics capabilities = mCameraManager.getCameraCharacteristics(id);
128             assertNotNull("Camera characteristics shouldn't be null", capabilities);
129             List<Key<?>> keysNeedingPermission = capabilities.getKeysNeedingPermission();
130             if (keysNeedingPermission == null) {
131                 continue;
132             }
133             List<Key<?>> keys = capabilities.getKeys();
134             assertNotNull("Camera characteristics key list shouldn't be null", keys);
135             for (Key<?> key : keysNeedingPermission) {
136                 assertEquals("Key " + key.getName() + " needing permission is part of the" +
137                         " available characteristics keys", -1, keys.indexOf(key));
138                 assertNull("Key " + key.getName() + " needing permission must not present" +
139                         " in camera characteristics", capabilities.get(key));
140             }
141         }
142     }
143 
144     /**
145      * Add and remove availability listeners should work without permission.
146      */
147     @Presubmit
testAvailabilityCallback()148     public void testAvailabilityCallback() throws Exception {
149         DummyCameraListener availabilityListener = new DummyCameraListener();
150         // Remove a not-registered listener is a no-op.
151         mCameraManager.unregisterAvailabilityCallback(availabilityListener);
152         mCameraManager.registerAvailabilityCallback(availabilityListener, mHandler);
153         mCameraManager.unregisterAvailabilityCallback(availabilityListener);
154         mCameraManager.registerAvailabilityCallback(availabilityListener, mHandler);
155         mCameraManager.registerAvailabilityCallback(availabilityListener, mHandler);
156         mCameraManager.unregisterAvailabilityCallback(availabilityListener);
157         // Remove a previously-added listener second time is a no-op.
158         mCameraManager.unregisterAvailabilityCallback(availabilityListener);
159     }
160 
161     private class DummyCameraListener extends CameraManager.AvailabilityCallback {
162         @Override
onCameraAvailable(String cameraId)163         public void onCameraAvailable(String cameraId) {
164         }
165 
166         @Override
onCameraUnavailable(String cameraId)167         public void onCameraUnavailable(String cameraId) {
168         }
169     }
170 
openCamera(String cameraId)171     private void openCamera(String cameraId) throws Exception {
172         mCamera = (new BlockingCameraManager(mCameraManager)).openCamera(
173                 cameraId, mCameraListener, mHandler);
174     }
175 
toList(int[] array)176     private static List<Integer> toList(int[] array) {
177         List<Integer> list = new ArrayList<Integer>();
178         for (int i  : array) {
179             list.add(i);
180         }
181         return list;
182     }
183 
closeCamera()184     private void closeCamera() {
185         if (mCamera != null) {
186             mCamera.close();
187             mCameraListener.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS);
188             mCamera = null;
189         }
190     }
191 }
192