1 /* 2 * Copyright (C) 2013 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.ex.camera2.portability; 18 19 import android.content.Context; 20 import android.os.Build; 21 22 import com.android.ex.camera2.portability.debug.Log; 23 import com.android.ex.camera2.portability.util.SystemProperties; 24 25 /** 26 * A factory class for {@link CameraAgent}. 27 * 28 * <p>The choice of framework API to use can be made automatically based on the 29 * system API level, explicitly forced by the client app, or overridden entirely 30 * by setting the system property com.camera2.portability.fwk_api to 1 or 2.</p> 31 */ 32 public class CameraAgentFactory { 33 private static final Log.Tag TAG = new Log.Tag("CamAgntFact"); 34 35 /** Android release replacing the Camera class with the camera2 package. */ 36 private static final int FIRST_SDK_WITH_API_2 = 21; 37 38 // The debugging override, which overrides *all* API level selections if set 39 // to API_LEVEL_OVERRIDE_API{1,2}; otherwise, this has no effect. Note that 40 // we check this once when the library is first loaded so that #recycle() 41 // doesn't try to clean up the wrong type of CameraAgent. 42 private static final String API_LEVEL_OVERRIDE_KEY = "camera2.portability.force_api"; 43 private static final String API_LEVEL_OVERRIDE_DEFAULT = "0"; 44 private static final String API_LEVEL_OVERRIDE_API1 = "1"; 45 private static final String API_LEVEL_OVERRIDE_API2 = "2"; 46 private static final String API_LEVEL_OVERRIDE_VALUE = 47 SystemProperties.get(API_LEVEL_OVERRIDE_KEY, API_LEVEL_OVERRIDE_DEFAULT); 48 49 private static CameraAgent sAndroidCameraAgent; 50 private static CameraAgent sAndroidCamera2Agent; 51 private static int sAndroidCameraAgentClientCount; 52 private static int sAndroidCamera2AgentClientCount; 53 54 /** 55 * Used to indicate which camera framework should be used. 56 */ 57 public static enum CameraApi { 58 /** Automatically select based on the device's SDK level. */ 59 AUTO, 60 61 /** Use the {@link android.hardware.Camera} class. */ 62 API_1, 63 64 /** Use the {@link android.hardware.camera2} package. */ 65 API_2 66 }; 67 68 private static CameraApi highestSupportedApi() { 69 // TODO: Check SDK_INT instead of RELEASE before L launch 70 if (Build.VERSION.SDK_INT >= FIRST_SDK_WITH_API_2 || Build.VERSION.CODENAME.equals("L")) { 71 return CameraApi.API_2; 72 } else { 73 return CameraApi.API_1; 74 } 75 } 76 77 private static CameraApi validateApiChoice(CameraApi choice) { 78 if (API_LEVEL_OVERRIDE_VALUE.equals(API_LEVEL_OVERRIDE_API1)) { 79 Log.d(TAG, "API level overridden by system property: forced to 1"); 80 return CameraApi.API_1; 81 } else if (API_LEVEL_OVERRIDE_VALUE.equals(API_LEVEL_OVERRIDE_API2)) { 82 Log.d(TAG, "API level overridden by system property: forced to 2"); 83 return CameraApi.API_2; 84 } 85 86 if (choice == null) { 87 Log.w(TAG, "null API level request, so assuming AUTO"); 88 choice = CameraApi.AUTO; 89 } 90 if (choice == CameraApi.AUTO) { 91 choice = highestSupportedApi(); 92 } 93 94 return choice; 95 } 96 97 /** 98 * Returns the android camera implementation of 99 * {@link com.android.camera.cameradevice.CameraAgent}. 100 * 101 * <p>To clean up the resources allocated by this call, be sure to invoke 102 * {@link #recycle(boolean)} with the same {@code api} value provided 103 * here.</p> 104 * 105 * @param context The application context. 106 * @param api Which camera framework to use. 107 * @return The {@link CameraAgent} to control the camera device. 108 * 109 * @throws UnsupportedOperationException If {@code CameraApi.API_2} was 110 * requested on an unsupported device. 111 */ 112 public static synchronized CameraAgent getAndroidCameraAgent(Context context, CameraApi api) { 113 api = validateApiChoice(api); 114 115 if (api == CameraApi.API_1) { 116 if (sAndroidCameraAgent == null) { 117 sAndroidCameraAgent = new AndroidCameraAgentImpl(); 118 sAndroidCameraAgentClientCount = 1; 119 } else { 120 ++sAndroidCameraAgentClientCount; 121 } 122 return sAndroidCameraAgent; 123 } else { // API_2 124 if (highestSupportedApi() == CameraApi.API_1) { 125 throw new UnsupportedOperationException("Camera API_2 unavailable on this device"); 126 } 127 128 if (sAndroidCamera2Agent == null) { 129 sAndroidCamera2Agent = new AndroidCamera2AgentImpl(context); 130 sAndroidCamera2AgentClientCount = 1; 131 } else { 132 ++sAndroidCamera2AgentClientCount; 133 } 134 return sAndroidCamera2Agent; 135 } 136 } 137 138 /** 139 * Recycles the resources. Always call this method when the activity is 140 * stopped. 141 * 142 * @param api Which camera framework handle to recycle. 143 * 144 * @throws UnsupportedOperationException If {@code CameraApi.API_2} was 145 * requested on an unsupported device. 146 */ 147 public static synchronized void recycle(CameraApi api) { 148 api = validateApiChoice(api); 149 150 if (api == CameraApi.API_1) { 151 if (--sAndroidCameraAgentClientCount == 0 && sAndroidCameraAgent != null) { 152 sAndroidCameraAgent.recycle(); 153 sAndroidCameraAgent = null; 154 } 155 } else { // API_2 156 if (highestSupportedApi() == CameraApi.API_1) { 157 throw new UnsupportedOperationException("Camera API_2 unavailable on this device"); 158 } 159 160 if (--sAndroidCamera2AgentClientCount == 0 && sAndroidCamera2Agent != null) { 161 sAndroidCamera2Agent.recycle(); 162 sAndroidCamera2Agent = null; 163 } 164 } 165 } 166 } 167