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
17package com.android.incallui;
18
19import android.content.Context;
20import android.hardware.camera2.CameraAccessException;
21import android.hardware.camera2.CameraCharacteristics;
22import android.hardware.camera2.CameraManager;
23import java.util.Collections;
24import java.util.Set;
25import java.util.concurrent.ConcurrentHashMap;
26
27/** Used to track which camera is used for outgoing video. */
28public class InCallCameraManager {
29
30  private final Set<Listener> mCameraSelectionListeners =
31      Collections.newSetFromMap(new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
32  /** The camera ID for the front facing camera. */
33  private String mFrontFacingCameraId;
34  /** The camera ID for the rear facing camera. */
35  private String mRearFacingCameraId;
36  /** The currently active camera. */
37  private boolean mUseFrontFacingCamera;
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 mIsInitialized = false;
43  /** The context. */
44  private Context mContext;
45
46  /**
47   * Initializes the InCall CameraManager.
48   *
49   * @param context The current context.
50   */
51  public InCallCameraManager(Context context) {
52    mUseFrontFacingCamera = true;
53    mContext = 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   */
61  public void setUseFrontFacingCamera(boolean useFrontFacingCamera) {
62    mUseFrontFacingCamera = useFrontFacingCamera;
63    for (Listener listener : mCameraSelectionListeners) {
64      listener.onActiveCameraSelectionChanged(mUseFrontFacingCamera);
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   */
73  public boolean isUsingFrontFacingCamera() {
74    return mUseFrontFacingCamera;
75  }
76
77  /**
78   * Determines the active camera ID.
79   *
80   * @return The active camera ID.
81   */
82  public String getActiveCameraId() {
83    maybeInitializeCameraList(mContext);
84
85    if (mUseFrontFacingCamera) {
86      return mFrontFacingCameraId;
87    } else {
88      return mRearFacingCameraId;
89    }
90  }
91
92  /** Calls when camera permission is granted by user. */
93  public void onCameraPermissionGranted() {
94    for (Listener listener : mCameraSelectionListeners) {
95      listener.onCameraPermissionGranted();
96    }
97  }
98
99  /**
100   * Get the list of cameras available for use.
101   *
102   * @param context The context.
103   */
104  private void maybeInitializeCameraList(Context context) {
105    if (mIsInitialized || 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          mFrontFacingCameraId = cameraIds[i];
145        } else if (facingCharacteristic == CameraCharacteristics.LENS_FACING_BACK) {
146          mRearFacingCameraId = cameraIds[i];
147        }
148      }
149    }
150
151    mIsInitialized = true;
152    Log.v(this, "initializeCameraList : done");
153  }
154
155  public void addCameraSelectionListener(Listener listener) {
156    if (listener != null) {
157      mCameraSelectionListeners.add(listener);
158    }
159  }
160
161  public void removeCameraSelectionListener(Listener listener) {
162    if (listener != null) {
163      mCameraSelectionListeners.remove(listener);
164    }
165  }
166
167  public interface Listener {
168
169    void onActiveCameraSelectionChanged(boolean isUsingFrontFacingCamera);
170
171    void onCameraPermissionGranted();
172  }
173}
174