summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jayant Chowdhary <jchowdhary@google.com> 2019-09-24 20:05:18 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-09-24 20:05:18 +0000
commit7f9a4c9e8cc8d32a6128c9c55d576793a2f0ecf8 (patch)
tree696e8acc02ec213e117758d168d44668051cac81
parentc022a8d13a811419e9efdd9d9c5748bbace9e9f2 (diff)
parent4feeee88911503cc365b223a712437abcd91c94f (diff)
Merge changes from topic "system-camera-cts"
* changes: Allow com.android.shell to get RECORD_AUDIO permissions. CameraManager: Add @TestApi method getCameraIdListNoLazy().
-rw-r--r--api/test-current.txt4
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java146
-rw-r--r--packages/Shell/AndroidManifest.xml2
3 files changed, 125 insertions, 27 deletions
diff --git a/api/test-current.txt b/api/test-current.txt
index 51b569f029d0..0e93738b28f4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -925,6 +925,10 @@ package android.hardware.camera2 {
field public static final int SESSION_OPERATION_MODE_VENDOR_START = 32768; // 0x8000
}
+ public final class CameraManager {
+ method public String[] getCameraIdListNoLazy() throws android.hardware.camera2.CameraAccessException;
+ }
+
}
package android.hardware.display {
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index c8276b25c52d..fc90096e5add 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.Context;
import android.hardware.CameraInfo;
import android.hardware.CameraStatus;
@@ -47,6 +48,7 @@ import android.view.WindowManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
@@ -109,6 +111,21 @@ public final class CameraManager {
}
/**
+ * Similar to getCameraIdList(). However, getCamerIdListNoLazy() necessarily communicates with
+ * cameraserver in order to get the list of camera ids. This is to faciliate testing since some
+ * camera ids may go 'offline' without callbacks from cameraserver because of changes in
+ * SYSTEM_CAMERA permissions (though this is not a changeable permission, tests may call
+ * adopt(drop)ShellPermissionIdentity() and effectively change their permissions). This call
+ * affects the camera ids returned by getCameraIdList() as well. Tests which do adopt shell
+ * permission identity should not mix getCameraIdList() and getCameraListNoLazyCalls().
+ */
+ /** @hide */
+ @TestApi
+ public String[] getCameraIdListNoLazy() throws CameraAccessException {
+ return CameraManagerGlobal.get().getCameraIdListNoLazy();
+ }
+
+ /**
* Register a callback to be notified about camera device availability.
*
* <p>Registering the same callback again will replace the handler with the
@@ -995,35 +1012,27 @@ public final class CameraManager {
// Camera service is now down, leave mCameraService as null
}
}
-
- /**
- * Get a list of all camera IDs that are at least PRESENT; ignore devices that are
- * NOT_PRESENT or ENUMERATING, since they cannot be used by anyone.
- */
- public String[] getCameraIdList() {
+ private String[] extractCameraIdListLocked() {
String[] cameraIds = null;
- synchronized(mLock) {
- // Try to make sure we have an up-to-date list of camera devices.
- connectCameraServiceLocked();
-
- int idCount = 0;
- for (int i = 0; i < mDeviceStatus.size(); i++) {
- int status = mDeviceStatus.valueAt(i);
- if (status == ICameraServiceListener.STATUS_NOT_PRESENT ||
- status == ICameraServiceListener.STATUS_ENUMERATING) continue;
- idCount++;
- }
- cameraIds = new String[idCount];
- idCount = 0;
- for (int i = 0; i < mDeviceStatus.size(); i++) {
- int status = mDeviceStatus.valueAt(i);
- if (status == ICameraServiceListener.STATUS_NOT_PRESENT ||
- status == ICameraServiceListener.STATUS_ENUMERATING) continue;
- cameraIds[idCount] = mDeviceStatus.keyAt(i);
- idCount++;
- }
+ int idCount = 0;
+ for (int i = 0; i < mDeviceStatus.size(); i++) {
+ int status = mDeviceStatus.valueAt(i);
+ if (status == ICameraServiceListener.STATUS_NOT_PRESENT
+ || status == ICameraServiceListener.STATUS_ENUMERATING) continue;
+ idCount++;
}
-
+ cameraIds = new String[idCount];
+ idCount = 0;
+ for (int i = 0; i < mDeviceStatus.size(); i++) {
+ int status = mDeviceStatus.valueAt(i);
+ if (status == ICameraServiceListener.STATUS_NOT_PRESENT
+ || status == ICameraServiceListener.STATUS_ENUMERATING) continue;
+ cameraIds[idCount] = mDeviceStatus.keyAt(i);
+ idCount++;
+ }
+ return cameraIds;
+ }
+ private static void sortCameraIds(String[] cameraIds) {
// The sort logic must match the logic in
// libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
Arrays.sort(cameraIds, new Comparator<String>() {
@@ -1054,6 +1063,89 @@ public final class CameraManager {
return s1.compareTo(s2);
}
}});
+
+ }
+
+ public static boolean cameraStatusesContains(CameraStatus[] cameraStatuses, String id) {
+ for (CameraStatus c : cameraStatuses) {
+ if (c.cameraId.equals(id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String[] getCameraIdListNoLazy() {
+ CameraStatus[] cameraStatuses;
+ ICameraServiceListener.Stub testListener = new ICameraServiceListener.Stub() {
+ @Override
+ public void onStatusChanged(int status, String id) throws RemoteException {
+ }
+ @Override
+ public void onTorchStatusChanged(int status, String id) throws RemoteException {
+ }
+ @Override
+ public void onCameraAccessPrioritiesChanged() {
+ }};
+
+ String[] cameraIds = null;
+ synchronized (mLock) {
+ connectCameraServiceLocked();
+ try {
+ // The purpose of the addListener, removeListener pair here is to get a fresh
+ // list of camera ids from cameraserver. We do this since for in test processes,
+ // changes can happen w.r.t non-changeable permissions (eg: SYSTEM_CAMERA
+ // permissions can be effectively changed by calling
+ // adopt(drop)ShellPermissionIdentity()).
+ // Camera devices, which have their discovery affected by these permission
+ // changes, will not have clients get callbacks informing them about these
+ // devices going offline (in real world scenarios, these permissions aren't
+ // changeable). Future calls to getCameraIdList() will reflect the changes in
+ // the camera id list after getCameraIdListNoLazy() is called.
+ cameraStatuses = mCameraService.addListener(testListener);
+ mCameraService.removeListener(testListener);
+ for (CameraStatus c : cameraStatuses) {
+ onStatusChangedLocked(c.status, c.cameraId);
+ }
+ Set<String> deviceCameraIds = mDeviceStatus.keySet();
+ ArrayList<String> deviceIdsToRemove = new ArrayList<String>();
+ for (String deviceCameraId : deviceCameraIds) {
+ // Its possible that a device id was removed without a callback notifying
+ // us. This may happen in case a process 'drops' system camera permissions
+ // (even though the permission isn't a changeable one, tests may call
+ // adoptShellPermissionIdentity() and then dropShellPermissionIdentity().
+ if (!cameraStatusesContains(cameraStatuses, deviceCameraId)) {
+ deviceIdsToRemove.add(deviceCameraId);
+ }
+ }
+ for (String id : deviceIdsToRemove) {
+ onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, id);
+ }
+ } catch (ServiceSpecificException e) {
+ // Unexpected failure
+ throw new IllegalStateException("Failed to register a camera service listener",
+ e);
+ } catch (RemoteException e) {
+ // Camera service is now down, leave mCameraService as null
+ }
+ cameraIds = extractCameraIdListLocked();
+ }
+ sortCameraIds(cameraIds);
+ return cameraIds;
+ }
+
+ /**
+ * Get a list of all camera IDs that are at least PRESENT; ignore devices that are
+ * NOT_PRESENT or ENUMERATING, since they cannot be used by anyone.
+ */
+ public String[] getCameraIdList() {
+ String[] cameraIds = null;
+ synchronized (mLock) {
+ // Try to make sure we have an up-to-date list of camera devices.
+ connectCameraServiceLocked();
+ cameraIds = extractCameraIdListLocked();
+ }
+ sortCameraIds(cameraIds);
return cameraIds;
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b2ff4b3268b2..e767bccc7b4a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -172,6 +172,8 @@
<!-- Permissions needed to test system only camera devices -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.SYSTEM_CAMERA" />
+ <!-- Permissions needed for CTS camera test: RecordingTest.java when assuming shell id -->
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- Permission needed to enable/disable Bluetooth/Wifi -->
<uses-permission android:name="android.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED" />
<uses-permission android:name="android.permission.MANAGE_WIFI_WHEN_WIRELESS_CONSENT_REQUIRED" />