1/*
2 * Copyright (C) 2015 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.car;
18
19import android.content.Context;
20import android.car.hardware.camera.CarCameraState;
21import android.car.hardware.camera.ICarCamera;
22import android.graphics.Rect;
23import android.util.Log;
24
25import java.io.PrintWriter;
26import java.util.Collection;
27import java.util.HashMap;
28import java.util.Set;
29
30public class CarCameraService extends ICarCamera.Stub implements CarServiceBase {
31    public static final boolean DBG = false;
32    public static final String  TAG = CarLog.TAG_CAMERA + ".CarCameraService";
33
34    private final Context mContext;
35    private long mModule;
36    private final HashMap<Integer, Long> mDeviceMap;
37
38    public CarCameraService(Context context) {
39        mContext = context;
40        mDeviceMap = new HashMap<Integer, Long>();
41    }
42
43    @Override
44    public synchronized void init() {
45        if (DBG) {
46            Log.d(TAG, "init called");
47        }
48        mModule = nativeOpen();
49
50        if (mModule != 0) {
51            int[] cameraType = nativeGetSupportedCameras(mModule);
52
53            if (cameraType != null) {
54                for (int i : cameraType) {
55                    long devicePtr = nativeGetDevice(mModule, i);
56                    if (devicePtr == 0) {
57                        Log.e(TAG, "Null device pointer returned for cameraType = " + i);
58                    } else {
59                        mDeviceMap.put(i, devicePtr);
60                    }
61                }
62            } else {
63                Log.e(TAG, "No car cameras are supported");
64            }
65        } else {
66            Log.w(TAG, "Cannot load camera module");
67        }
68    }
69
70    @Override
71    public synchronized void release() {
72        if (DBG) {
73            Log.d(TAG, "release called");
74        }
75        Collection<Long> devices = mDeviceMap.values();
76        for (Long device : devices) {
77            nativeClose(device);
78        }
79        mDeviceMap.clear();
80        mModule = 0;
81    }
82
83    @Override
84    public void dump(PrintWriter writer) {
85        // TODO
86    }
87
88    @Override
89    public int[] getCameraList() {
90        if (DBG) {
91            Log.d(TAG, "getCameraList called");
92        }
93        Set<Integer> keySet;
94        synchronized (this) {
95            keySet = mDeviceMap.keySet();
96        }
97
98        int keySetSize = keySet.size();
99
100        if (keySetSize > 0) {
101            int[] keyArray = new int[keySet.size()];
102            int i = 0;
103            for (Integer key : keySet) {
104                keyArray[i++] = key.intValue();
105            }
106            return keyArray;
107        } else {
108            return null;
109        }
110    }
111
112    @Override
113    public int getCapabilities(int cameraType) {
114        if (DBG) {
115            Log.d(TAG, "getCapabilities called, type = " + String.valueOf(cameraType));
116        }
117        synchronized (this) {
118            long device = getDeviceIdLocked(cameraType);
119            return nativeGetCapabilities(device);
120        }
121    }
122
123    @Override
124    public Rect getCameraCrop(int cameraType) {
125        Rect rect;
126        synchronized (this) {
127            long device = getDeviceIdLocked(cameraType);
128            rect = nativeGetCameraCrop(device);
129        }
130        if(DBG && (rect != null)) {
131            Log.d(TAG, "getCameraCrop called:  " + rect.toString());
132        }
133        return rect;
134    }
135
136    @Override
137    public void setCameraCrop(int cameraType, Rect rect) {
138        if (DBG) {
139            Log.d(TAG, "setCameraCrop called." + rect.toString());
140        }
141        synchronized (this) {
142            long device = getDeviceIdLocked(cameraType);
143            nativeSetCameraCrop(device, rect);
144        }
145    }
146
147    @Override
148    public Rect getCameraPosition(int cameraType) {
149        Rect rect;
150        synchronized (this) {
151            long device = getDeviceIdLocked(cameraType);
152            rect = nativeGetCameraPosition(device);
153        }
154        if(DBG && (rect != null)) {
155            Log.d(TAG, "getCameraPosition called:  " + rect.toString());
156        }
157        return rect;
158    }
159
160    @Override
161    public void setCameraPosition(int cameraType, Rect rect) {
162        if (DBG) {
163            Log.d(TAG, "setCameraPosition called." + rect.toString());
164        }
165        synchronized (this) {
166            long device = getDeviceIdLocked(cameraType);
167            nativeSetCameraPosition(device, rect);
168        }
169    }
170
171    @Override
172    public CarCameraState getCameraState(int cameraType) {
173        CarCameraState state;
174        synchronized (this) {
175            long device = getDeviceIdLocked(cameraType);
176            state = nativeGetCameraState(device);
177        }
178        if(DBG && (state != null)) {
179            Log.d(TAG, "getCameraState called: " + state.toString());
180        }
181        return state;
182    }
183
184    @Override
185    public void setCameraState(int cameraType, CarCameraState state) {
186        if (DBG) {
187            Log.d(TAG, "setCameraState called.  state: " + state.toString());
188        }
189        synchronized (this) {
190            long device = getDeviceIdLocked(cameraType);
191            nativeSetCameraState(device, state);
192        }
193    }
194
195    /**
196     * Validates that the cameraType is available and ready to be used.
197     * @param cameraType
198     * @return
199     */
200    private long getDeviceIdLocked(int cameraType) {
201        Long deviceId = mDeviceMap.get(cameraType);
202
203        if (deviceId == null) {
204            throw new IllegalArgumentException("cameraType " + cameraType + " doesn't exist in"
205                    + "device map");
206        }
207        return deviceId;
208    }
209
210    /*
211     * Native function definitions
212     */
213    private native long nativeOpen();
214    private native void nativeClose(long module);
215    private native int[] nativeGetSupportedCameras(long module);
216    private native long nativeGetDevice(long module, int cameraType);
217    private native int nativeGetCapabilities(long device);
218    private native Rect nativeGetCameraCrop(long device);
219    private native void nativeSetCameraCrop(long device, Rect rect);
220    private native Rect nativeGetCameraPosition(long device);
221    private native void nativeSetCameraPosition(long device, Rect rect);
222    private native CarCameraState nativeGetCameraState(long device);
223    private native void nativeSetCameraState(long device, CarCameraState state);
224}
225