轉(zhuǎn)自:http://blog.csdn.net/wxzking/article/details/6384576
Android2.2及其以前的版本都不支持多camera。Android2.3中,camera的硬件接口中增加了對多camera的支持。由于某些原因,不能直接移植Android2.3,但又要支持多camera,所以只能參考Android2.3版本,在2.2上添加接口,支持多camera。
接下來,我將從application層開始,貫穿framework,直到hardware層,逐層介紹如何去支持多camera。
一、Application層支持多camera
1、camera.java文件
首先是Packages/apps/camera/src/com/android/camera/camera.java文件,它是camera應(yīng)用程序的主體。另外在Framework/base/core/java/android/hardware/下也有一個camera.java文件,它應(yīng)該是framework與application之間的接口文件。請不要將這兩個文件混淆。在application的camera.java中,我添加如下的code。
Import了一個新類,叫做CameraInfo,用它來存儲camera的信息,其定義在文件Framework/base/core/java/android/hardware/camera.java中。
CODE:
import android.hardware.Camera.CameraInfo;
增加兩個私有變量,CODE如下:
// multiple cameras support private int mNumberOfCameras; private int mCameraId;
mNumberOfCameras用來記錄手機上camera的數(shù)量,可以通過函數(shù)CameraHolder.instance().getNumberOfCameras()來獲得;mCameraId用來記錄某個camera的ID,camera的ID可以從CameraInfo中獲取。
當(dāng)我們獲取了camera的總數(shù)后,可以通過函數(shù)CameraHolder.instance().getCameraInfo(),逐個去獲取每個camera的信息,選擇自己想要的camera,然后通過函數(shù)CameraHolder.instance().setCameraId()去設(shè)置當(dāng)前要用的camera。
這里需要說明的是,在Android2.3中,只增加了getNumberOfCameras()和getCameraInfo()這兩個接口,同時修改了CameraHolder.instance().open()接口,該接口對應(yīng)底層的connect()。我為了堅持Android2.2的所有接口不變的原則,只移植了這兩個接口,沒有修改connect(),但同時增加了另一個接口setCameraId()。通過setCameraId()告訴camera的HAL層,當(dāng)前所要的camera,如果不調(diào)用該接口,系統(tǒng)就按照Android2.2原來的配置運行。好了,下面我們繼續(xù)描述code。
我修改了onCreate()函數(shù),CODE如下:
@Override public void onCreate(Bundle icicle) { super.onCreate(icicle);
setContentView(R.layout.camera); mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview);
mPreferences = PreferenceManager.getDefaultSharedPreferences(this); CameraSettings.upgradePreferences(mPreferences);
mNumberOfCameras = CameraHolder.instance().getNumberOfCameras(); for(int I = 0; I < mNumberOfCameras; I++)
{
CameraInfo info = CameraHolder.instance().getCameraInfo()[I];
If(CameraInfo.CAMERA_FACING_FRONT == info.facing)
{
mCameraId = I;
break;
}
}
CameraHolder.instance().setCameraId(mCameraId);
mQuickCapture = getQuickCaptureSettings();
……
至此Packages/apps/camera/src/com/android/camera/camera.java文件修改完畢,接下來我們修改Packages/apps/camera/src/com/android/camera/CameraHolder.java。camera.java是通過調(diào)用CameraHolder.java的接口來實現(xiàn)功能的。
2、CameraHolder.java文件
在CameraHolder.java文件中,同樣得import CameraInfo類。CODE如下:
import android.hardware.Camera.CameraInfo;
添加三個私有變量:
private int mNumberOfCameras; private int mCameraId = -1; private CameraInfo[] mInfo;
這三個變量的意義一目了然,不做多講。
修改了CameraHolder()函數(shù):
private CameraHolder() { HandlerThread ht = new HandlerThread("CameraHolder"); ht.start(); mHandler = new MyHandler(ht.getLooper()); mNumberOfCameras = android.hardware.Camera.getNumberOfCameras(); mInfo = new CameraInfo[mNumberOfCameras]; for (int i = 0; i < mNumberOfCameras; i++) { mInfo[i] = new CameraInfo(); android.hardware.Camera.getCameraInfo(i, mInfo[i]); } }
CameraHolder()中調(diào)用android.hardware.Camera.getNumberOfCameras()獲取了camera的總數(shù),賦值給mNumberOfCameras,同時創(chuàng)建了相應(yīng)數(shù)目的CameraInfo數(shù)組,并通過函數(shù)android.hardware.Camera.getCameraInfo()將camera的信息都存儲在mInfo中。同時增加了下面三個接口函數(shù): public int getNumberOfCameras() { return mNumberOfCameras; }
public CameraInfo[] getCameraInfo() { return mInfo; } public int setCameraId(int cameraId) { return android.hardware.Camera.setCameraId(cameraId); }
在application中,修改上述兩個文件即可。下面我們將描述framework中的修改。
下面我將在camera應(yīng)用程序的preference菜單(也就是我們看到的第一個菜單,可以設(shè)置圖像大小,場景等)中,添加select_camera項,其有兩個成員,分別為:back_camera和front_camera,默認(rèn)選中back_camera。
接下來,我將按照文件依次介紹如何修改菜單并支持camera切換。
1. camera_preferences.xml文件
其位于Packages/apps/camera/res/xml/camera_preferences.xml。
camera_preferences.xml文件中,包含了camera應(yīng)用程序所支持的所有preference菜單。首先需要在這個文件中添加如下code:
<ListPreference camera:key="pref_camera_id_key"
camera:defaultValue="@string/pref_camera_id_default"
camera:title="@string/pref_camera_id_title"
camera:entries="@array/pref_camera_id_entries"
camera:entryValues="@array/pref_camera_id_entryvalues" />
該菜單項的名稱為:pref_camera_id_title,其定義為:Select_camera;默認(rèn)選中的是pref_camera_id_default,其定義為:back_camera;菜單項包含的成員為:pref_camera_id_entries,其定義在文件arrays.xml中,為:pref_camera_id_entry_back和pref_camera_id_entry_front,即Back_camera和Front_camera。菜單項成員對應(yīng)的鍵值為pref_camera_id_entryvalues,其定義為:back_camera和front_camera。
2. strings.xml文件
其位于Packages/apps/camera/ res/values/strings.xml。
在strings.xml文件中添加如下字符串的定義:
<string name="pref_camera_id_title">Select_camera</string>
<string name="pref_camera_id_entry_back">Back_camera</string>
<string name="pref_camera_id_entry_front">Front_camera</string>
<string name="pref_camera_id_default" translatable="false">back_camera</string>
3. arrays.xml文件
其位于Packages/apps/camera/ res/values/ arrays.xml。
在arrays.xml文件中添加如下定義,其定義了菜單項成員及其鍵值。
<string-array name="pref_camera_id_entries" translatable="false">
<item>@string/pref_camera_id_entry_back</item>
<item>@string/pref_camera_id_entry_front</item>
</string-array>
<string-array name="pref_camera_id_entryvalues" translatable="false">
<item>back_camera</item>
<item>front_camera</item>
</string-array>
4. CameraSettings.java文件
其位于Packages/apps/camera/ src/com/android/camera/CameraSettings.java。
首先定義:
public static final String KEY_CAMERA_ID = "pref_camera_id_key";
這個與文件camera_preferences.xml中的菜單項對應(yīng)。
然后在函數(shù):
private void initPreference(PreferenceGroup group)中添加如下的code:
ListPreference cameraId = group.findPreference(KEY_CAMERA_ID);
該code的意思是在camera preference中去找鍵值為KEY_CAMERA_ID的菜單項。如果不存在則返回null,否則返回該菜單項。
函數(shù)public ListPreference findPreference(String key)的定義在文件
PreferenceGroup.java中。
緊接著,又添加code:
if (cameraId != null) {
filterUnsupportedOptions(group, cameraId,
mParameters.getSupportedCameraId());}
函數(shù)mParameters.getSupportedCameraId()將獲取camera 硬件支持的camera切換的項,其定義在文件Framework/base/core/java/android/hardware/camera.java中。cameraId相當(dāng)于從camera_preferences.xml中獲取的camera切換的項,它倆之間需要做個匹配,如果camera硬件支持的項不存在或者只有一項,則需要從group中去掉camera切換的菜單。
同時,添加如下兩個函數(shù):
public static int getCameraId(Parameters parameters){
if(parameters.getCameraIdString().equals("front_camera"))
return 1;
else
return 0;
}
public static void setCameraId(int cameraId, Parameters parameters){
parameters.setCamId(cameraId);
}
通過它們可以獲取或者設(shè)置camera的ID。
5. Camera.java文件
其位于Packages/apps/camera/ src/com/android/camera/ Camera.java。
在函數(shù)public void onCreate(Bundle icicle)中添加:
mCameraId = 0;
CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
CameraHolder.instance().setCameraId(mCameraId);
設(shè)置mCameraId為0,即表示默認(rèn)打開后置camera。
將函數(shù)private void ensureCameraDevice()改為:
private void ensureCameraDevice() throws CameraHardwareException {
if (mCameraDevice == null) {
CameraHolder.instance().setCameraId(mCameraId);
mCameraDevice = CameraHolder.instance().open();
mInitialParams = mCameraDevice.getParameters();
}
}
在打開cameraDevice前,調(diào)用CameraHolder.instance().setCameraId(mCameraId)設(shè)置當(dāng)前需要打開的camera的ID。
在函數(shù)private void updateCameraParametersPreference()中添加:
String cameraId = mPreferences.getString(CameraSettings.KEY_CAMERA_ID,
getString(R.string.pref_camera_id_default));
if (isSupported(cameraId, mParameters.getSupportedCameraId())) {
if (!mParameters.getCameraIdString().equals(cameraId)) {
mParameters.setCameraIdString(cameraId);
}
}
該函數(shù)是用來更新菜單設(shè)置的,
mPreferences.getString(CameraSettings.KEY_CAMERA_ID,
getString(R.string.pref_camera_id_default))獲取了鍵值KEY_CAMERA_ID對應(yīng)的菜單項當(dāng)前所選擇的項。isSupported(cameraId, mParameters.getSupportedCameraId())用來判斷該項是否是camera硬件所支持的項。如果是,使用
mParameters.getCameraIdString().equals(cameraId)來判斷該項是否與保存的cameraID是否一致,如果不一致,則使用mParameters.setCameraIdString(cameraId)更新保存值。通過這個函數(shù),當(dāng)用戶選擇菜單時,它就會用菜單上的變化更新當(dāng)前保存的值。
在函數(shù)private void onSharedPreferenceChanged()的末尾添加code:
int cameraId = CameraSettings.getCameraId(mParameters);
if (mCameraId != cameraId) {
switchCameraId(cameraId);
}
使用CameraSettings.getCameraId(mParameters)獲取目前保存的cameraID,讓它與mCameraId比較,如果不一致,則需要切換camera。函數(shù)switchCameraId()的定義如下:
private void switchCameraId(int cameraId) {
if (mPausing || !isCameraIdle()) return;
Log.v(TAG, "switch camera: new cameraID: " + cameraId + ", old cameraID: " + mCameraId);
mCameraId = cameraId;
CameraSettings.setCameraId(cameraId, mParameters);
stopPreview();
closeCamera();
// Remove the messages in the event queue.
mHandler.removeMessages(RESTART_PREVIEW);
// Reset variables
mJpegPictureCallbackTime = 0;
mZoomValue = 0;
// Reload the preferences.
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
CameraSettings.upgradePreferences(mPreferences);
// Restart the preview.
resetExposureCompensation();
//if (!restartPreview()) return;
restartPreview();
initializeZoom();
// Reload the UI.
if (mFirstTimeInitialized) {
initializeHeadUpDisplay();
}
}
6. CameraHeadUpDisplay.java文件
其位于Packages/apps/camera/ src/com/android/camera/ui/ CameraHeadUpDisplay.java。
在函數(shù)getListPreferences中添加CameraSettings.KEY_CAMERA_ID,即如下所示:
ListPreference prefs[] = getListPreferences(group,
CameraSettings.KEY_FOCUS_MODE,
CameraSettings.KEY_EXPOSURE,
CameraSettings.KEY_SCENE_MODE,
CameraSettings.KEY_PICTURE_SIZE,
CameraSettings.KEY_CAMERA_ID,
CameraSettings.KEY_JPEG_QUALITY,
CameraSettings.KEY_COLOR_EFFECT);
函數(shù)getListPreferences()定義在文件HeadUpDisplay.java中,其定義為:
protected static ListPreference[] getListPreferences(
PreferenceGroup group, String ... prefKeys) {
ArrayList<ListPreference> list = new ArrayList<ListPreference>();
for (String key : prefKeys) {
ListPreference pref = group.findPreference(key);
if (pref != null && pref.getEntries().length > 0) {
list.add(pref);
}
}
return list.toArray(new ListPreference[list.size()]);
}
這里的處理,就決定了哪些菜單項會被考慮去做顯示。所以必須添加CameraSettings.KEY_CAMERA_ID進去,否則菜單項是不會被顯示的。
7. Camera.java文件
其位于Framework/base/core/java/android/hardware/camera.java。
在這個文件中,主要是提供幾個獲取和設(shè)置cameraId的接口。首先定義:
private static final String KEY_CAMERA_ID = "cameraid";
public void setCamId(int cameraId)
{
if(0 == cameraId){
set(KEY_CAMERA_ID, "back_camera");
}
else{
set(KEY_CAMERA_ID, "front_camera");
}
}
public int getCamId()
{
if("back_camera" == get(KEY_CAMERA_ID)){
return 0;
}
else{
return 1;
}
}
public void setCameraIdString(String value)
{
set(KEY_CAMERA_ID, value);
}
public String getCameraIdString()
{
return get(KEY_CAMERA_ID);
}
public List<String> getSupportedCameraId() {
String str = get(KEY_CAMERA_ID + SUPPORTED_VALUES_SUFFIX);
return split(str);
}
這里需要說明的是,在camera HAL必須把硬件camera所支持的cameraID信息表示清楚,否則應(yīng)用程序不能正確顯示camera切換菜單。
8. CameraParameters.cpp文件
其位于Framework/base/libs/camera/CameraParameters.cpp。
在該文件中添加如下定義:
const char CameraParameters::KEY_CAMERA_ID[] = "cameraid"; const char CameraParameters::KEY_SUPPORTED_CAMERA_ID[] = "cameraid-values";
同時,CameraParameters.h中添加:
static const char KEY_CAMERA_ID[];
static const char KEY_SUPPORTED_CAMERA_ID[];
|