1bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong/* 2bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * Copyright (C) 2013 The Android Open Source Project 3bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * 4bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * Licensed under the Apache License, Version 2.0 (the "License"); 5bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * you may not use this file except in compliance with the License. 6bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * You may obtain a copy of the License at 7bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * 8bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * http://www.apache.org/licenses/LICENSE-2.0 9bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * 10bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * Unless required by applicable law or agreed to in writing, software 11bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * distributed under the License is distributed on an "AS IS" BASIS, 12bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * See the License for the specific language governing permissions and 14bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * limitations under the License. 15bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong */ 16bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong 17bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kongpackage com.android.ex.camera2.portability; 18bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong 19a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.content.Context; 2050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucherimport android.os.Build; 2150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 2250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucherimport com.android.ex.camera2.portability.debug.Log; 2350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucherimport com.android.ex.camera2.portability.util.SystemProperties; 24a0842b40441db5332a5290f941021636b1182761Sol Boucher 25bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong/** 264f425ba476d62b4be7078f2084af37cf306b31c6Sol Boucher * A factory class for {@link CameraAgent}. 2750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * 2850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * <p>The choice of framework API to use can be made automatically based on the 2950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * system API level, explicitly forced by the client app, or overridden entirely 3050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * by setting the system property com.camera2.portability.fwk_api to 1 or 2.</p> 31bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong */ 324f425ba476d62b4be7078f2084af37cf306b31c6Sol Boucherpublic class CameraAgentFactory { 3350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher private static final Log.Tag TAG = new Log.Tag("CamAgntFact"); 3450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 3550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher /** Android release replacing the Camera class with the camera2 package. */ 3650f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher private static final int FIRST_SDK_WITH_API_2 = 21; 3750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 3850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher // The debugging override, which overrides *all* API level selections if set 3950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher // to API_LEVEL_OVERRIDE_API{1,2}; otherwise, this has no effect. Note that 4050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher // we check this once when the library is first loaded so that #recycle() 4150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher // doesn't try to clean up the wrong type of CameraAgent. 4250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher private static final String API_LEVEL_OVERRIDE_KEY = "camera2.portability.force_api"; 4350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher private static final String API_LEVEL_OVERRIDE_DEFAULT = "0"; 4450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher private static final String API_LEVEL_OVERRIDE_API1 = "1"; 4550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher private static final String API_LEVEL_OVERRIDE_API2 = "2"; 4650f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher private static final String API_LEVEL_OVERRIDE_VALUE = 4750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher SystemProperties.get(API_LEVEL_OVERRIDE_KEY, API_LEVEL_OVERRIDE_DEFAULT); 48bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong 49a0842b40441db5332a5290f941021636b1182761Sol Boucher private static CameraAgent sAndroidCameraAgent; 5050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher private static CameraAgent sAndroidCamera2Agent; 514f425ba476d62b4be7078f2084af37cf306b31c6Sol Boucher private static int sAndroidCameraAgentClientCount; 5250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher private static int sAndroidCamera2AgentClientCount; 53bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong 54bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong /** 5550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * Used to indicate which camera framework should be used. 5650f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher */ 5750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher public static enum CameraApi { 5850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher /** Automatically select based on the device's SDK level. */ 5950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher AUTO, 6050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 6150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher /** Use the {@link android.hardware.Camera} class. */ 6250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher API_1, 6350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 6450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher /** Use the {@link android.hardware.camera2} package. */ 6550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher API_2 6650f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher }; 6750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 6850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher private static CameraApi highestSupportedApi() { 6950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher // TODO: Check SDK_INT instead of RELEASE before L launch 7050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (Build.VERSION.SDK_INT >= FIRST_SDK_WITH_API_2 || Build.VERSION.CODENAME.equals("L")) { 7150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher return CameraApi.API_2; 7250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } else { 7350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher return CameraApi.API_1; 7450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } 7550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } 7650f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 7750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher private static CameraApi validateApiChoice(CameraApi choice) { 7850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (API_LEVEL_OVERRIDE_VALUE.equals(API_LEVEL_OVERRIDE_API1)) { 7950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher Log.d(TAG, "API level overridden by system property: forced to 1"); 8050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher return CameraApi.API_1; 8150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } else if (API_LEVEL_OVERRIDE_VALUE.equals(API_LEVEL_OVERRIDE_API2)) { 8250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher Log.d(TAG, "API level overridden by system property: forced to 2"); 8350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher return CameraApi.API_2; 8450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } 8550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 8650f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (choice == null) { 8750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher Log.w(TAG, "null API level request, so assuming AUTO"); 8850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher choice = CameraApi.AUTO; 8950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } 9050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (choice == CameraApi.AUTO) { 9150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher choice = highestSupportedApi(); 9250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } 9350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 9450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher return choice; 9550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } 9650f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 9750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher /** 9850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * Returns the android camera implementation of 9950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * {@link com.android.camera.cameradevice.CameraAgent}. 10050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * 10150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * <p>To clean up the resources allocated by this call, be sure to invoke 10250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * {@link #recycle(boolean)} with the same {@code api} value provided 10350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * here.</p> 104bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * 10550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * @param context The application context. 10650f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * @param api Which camera framework to use. 1074f425ba476d62b4be7078f2084af37cf306b31c6Sol Boucher * @return The {@link CameraAgent} to control the camera device. 10850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * 10950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * @throws UnsupportedOperationException If {@code CameraApi.API_2} was 11050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * requested on an unsupported device. 111bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong */ 11250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher public static synchronized CameraAgent getAndroidCameraAgent(Context context, CameraApi api) { 11350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher api = validateApiChoice(api); 11450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 11550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (api == CameraApi.API_1) { 11650f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (sAndroidCameraAgent == null) { 117a0842b40441db5332a5290f941021636b1182761Sol Boucher sAndroidCameraAgent = new AndroidCameraAgentImpl(); 11850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher sAndroidCameraAgentClientCount = 1; 11950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } else { 12050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher ++sAndroidCameraAgentClientCount; 121a0842b40441db5332a5290f941021636b1182761Sol Boucher } 12250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher return sAndroidCameraAgent; 12350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } else { // API_2 12450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (highestSupportedApi() == CameraApi.API_1) { 12550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher throw new UnsupportedOperationException("Camera API_2 unavailable on this device"); 12650f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } 12750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 12850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (sAndroidCamera2Agent == null) { 12950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher sAndroidCamera2Agent = new AndroidCamera2AgentImpl(context); 13050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher sAndroidCamera2AgentClientCount = 1; 13150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } else { 13250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher ++sAndroidCamera2AgentClientCount; 13350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } 13450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher return sAndroidCamera2Agent; 135bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong } 136bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong } 137bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong 138bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong /** 139bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * Recycles the resources. Always call this method when the activity is 140bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong * stopped. 14150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * 14250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * @param api Which camera framework handle to recycle. 14350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * 14450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * @throws UnsupportedOperationException If {@code CameraApi.API_2} was 14550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher * requested on an unsupported device. 146bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong */ 14750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher public static synchronized void recycle(CameraApi api) { 14850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher api = validateApiChoice(api); 14950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 15050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (api == CameraApi.API_1) { 15150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (--sAndroidCameraAgentClientCount == 0 && sAndroidCameraAgent != null) { 15250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher sAndroidCameraAgent.recycle(); 15350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher sAndroidCameraAgent = null; 15450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } 15550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } else { // API_2 15650f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (highestSupportedApi() == CameraApi.API_1) { 15750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher throw new UnsupportedOperationException("Camera API_2 unavailable on this device"); 15850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } 15950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 16050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher if (--sAndroidCamera2AgentClientCount == 0 && sAndroidCamera2Agent != null) { 16150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher sAndroidCamera2Agent.recycle(); 16250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher sAndroidCamera2Agent = null; 16350f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher } 164bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong } 165bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong } 166bdaaaf5f0257168590fa8965e4d59b054636e6dfAngus Kong} 167