Home | History | Annotate | Download | only in portability
      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