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 com.android.incallui;
18 
19 import android.content.Context;
20 import android.hardware.camera2.CameraAccessException;
21 import android.hardware.camera2.CameraCharacteristics;
22 import android.hardware.camera2.CameraManager;
23 import java.util.Collections;
24 import java.util.Set;
25 import java.util.concurrent.ConcurrentHashMap;
26 
27 /** Used to track which camera is used for outgoing video. */
28 public class InCallCameraManager {
29 
30   private final Set<Listener> cameraSelectionListeners =
31       Collections.newSetFromMap(new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
32   /** The camera ID for the front facing camera. */
33   private String frontFacingCameraId;
34   /** The camera ID for the rear facing camera. */
35   private String rearFacingCameraId;
36   /** The currently active camera. */
37   private boolean useFrontFacingCamera;
38   /**
39    * Indicates whether the list of cameras has been initialized yet. Initialization is delayed until
40    * a video call is present.
41    */
42   private boolean isInitialized = false;
43   /** The context. */
44   private Context context;
45 
46   /**
47    * Initializes the InCall CameraManager.
48    *
49    * @param context The current context.
50    */
InCallCameraManager(Context context)51   public InCallCameraManager(Context context) {
52     useFrontFacingCamera = true;
53     this.context = context;
54   }
55 
56   /**
57    * Sets whether the front facing camera should be used or not.
58    *
59    * @param useFrontFacingCamera {@code True} if the front facing camera is to be used.
60    */
setUseFrontFacingCamera(boolean useFrontFacingCamera)61   public void setUseFrontFacingCamera(boolean useFrontFacingCamera) {
62     this.useFrontFacingCamera = useFrontFacingCamera;
63     for (Listener listener : cameraSelectionListeners) {
64       listener.onActiveCameraSelectionChanged(this.useFrontFacingCamera);
65     }
66   }
67 
68   /**
69    * Determines whether the front facing camera is currently in use.
70    *
71    * @return {@code True} if the front facing camera is in use.
72    */
isUsingFrontFacingCamera()73   public boolean isUsingFrontFacingCamera() {
74     return useFrontFacingCamera;
75   }
76 
77   /**
78    * Determines the active camera ID.
79    *
80    * @return The active camera ID.
81    */
getActiveCameraId()82   public String getActiveCameraId() {
83     maybeInitializeCameraList(context);
84 
85     if (useFrontFacingCamera) {
86       return frontFacingCameraId;
87     } else {
88       return rearFacingCameraId;
89     }
90   }
91 
92   /** Calls when camera permission is granted by user. */
onCameraPermissionGranted()93   public void onCameraPermissionGranted() {
94     for (Listener listener : cameraSelectionListeners) {
95       listener.onCameraPermissionGranted();
96     }
97   }
98 
99   /**
100    * Get the list of cameras available for use.
101    *
102    * @param context The context.
103    */
maybeInitializeCameraList(Context context)104   private void maybeInitializeCameraList(Context context) {
105     if (isInitialized || context == null) {
106       return;
107     }
108 
109     Log.v(this, "initializeCameraList");
110 
111     CameraManager cameraManager = null;
112     try {
113       cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
114     } catch (Exception e) {
115       Log.e(this, "Could not get camera service.");
116       return;
117     }
118 
119     if (cameraManager == null) {
120       return;
121     }
122 
123     String[] cameraIds = {};
124     try {
125       cameraIds = cameraManager.getCameraIdList();
126     } catch (CameraAccessException e) {
127       Log.d(this, "Could not access camera: " + e);
128       // Camera disabled by device policy.
129       return;
130     }
131 
132     for (int i = 0; i < cameraIds.length; i++) {
133       CameraCharacteristics c = null;
134       try {
135         c = cameraManager.getCameraCharacteristics(cameraIds[i]);
136       } catch (IllegalArgumentException e) {
137         // Device Id is unknown.
138       } catch (CameraAccessException e) {
139         // Camera disabled by device policy.
140       }
141       if (c != null) {
142         int facingCharacteristic = c.get(CameraCharacteristics.LENS_FACING);
143         if (facingCharacteristic == CameraCharacteristics.LENS_FACING_FRONT) {
144           frontFacingCameraId = cameraIds[i];
145         } else if (facingCharacteristic == CameraCharacteristics.LENS_FACING_BACK) {
146           rearFacingCameraId = cameraIds[i];
147         }
148       }
149     }
150 
151     isInitialized = true;
152     Log.v(this, "initializeCameraList : done");
153   }
154 
addCameraSelectionListener(Listener listener)155   public void addCameraSelectionListener(Listener listener) {
156     if (listener != null) {
157       cameraSelectionListeners.add(listener);
158     }
159   }
160 
removeCameraSelectionListener(Listener listener)161   public void removeCameraSelectionListener(Listener listener) {
162     if (listener != null) {
163       cameraSelectionListeners.remove(listener);
164     }
165   }
166 
167   public interface Listener {
168 
onActiveCameraSelectionChanged(boolean isUsingFrontFacingCamera)169     void onActiveCameraSelectionChanged(boolean isUsingFrontFacingCamera);
170 
onCameraPermissionGranted()171     void onCameraPermissionGranted();
172   }
173 }
174