在Andoird JB 4.2中,Camera的代码有非常大的变动,不管是frameworks,还是APP。逻辑更加严谨,google里的程序员真的很喜欢用设计模式,到处都可以看到设计模式的影子,刚刚拿到JB4.2源码的时候,我被绕晕了,一方面是代码变化太大,另一个最主要的因素还是自己功力不够。
现在,我们讨论一下如何在JB 4.2的Camera中实现一个功能:添加一个开关来控制拍照声音。
在4.2中实现应该说是更加简单了,因为系统在frameworks已经提供了一个方法:enableShutterSound(boolean enabled),其实我们可以在上层直接调用该方法来控制shutterSound,但是实践证明,它只能控制拍照的声音,而录制的声音会失效。
我们先跟踪一下这个方法,enableShutterSound(boolean enabled)方法在frameworks/base/core/java/android/hardware/Camera.java中,
public final boolean enableShutterSound(boolean enabled) {
...
return _enableShutterSound(enabled);
}
private native final boolean _enableShutterSound(boolean enabled);
在这里,它调用了一个native方法_enableShutterSound(boolean enabled),查看JNI目录,在
frameworks/base/core/jni/android_hardware_Camera.cpp文件中,如下代码:
static JNINativeMethod camMethods[] = {
...
{"_enableShutterSound","(Z)Z",(void *)anroid_hardware_Camera_enableShutterSound},
...
}
然后我们分析
android_hardware_Camera_enableShutterSound()
如下:
static jboolean android_hardware_Camera_enableShutterSound(JNIEnv *env, jobject thiz, jboolean enabled) {
...
status_t rc = camera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, value, 0);
...
}
然后转到frameworks/av/services/camera/libcameraservice/CameraClient.cpp。从4.1开始,Camera被更加重视了,将av放到base同等级别的目录下,呵呵。
status_t CameraClient::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
...
}else if(cmd == CAMERA_CMD_ENABLE_SHUTTER_SOUND) {
switch(arg1) {
case 0:
return enableShutterSound(false);
case 1:
return enableShutterSound(true);
default:
return BAD_VALUE;
}
return OK;
}
...
}
跟踪enableShutterSound方法,
status_t CameraClient::enableShutterSound(bool enable) {
...
if (enable){
mPlayShutterSound = true;
return OK;
}
...
mPlayShutterSound = false;
return false;
}
在snapshot taken callback,即
void CameraCilent::handleShutter(void) {
if(mPlayShutterSound) {
mCameraService->playSound(CameraService::SOUND_SHUTTER);
}
...
}
而在,录制视频的动作中,
status_t CameraCilent::startRecordingMode(){
...
mCameraService->playSound(CameraService::SOUND_RECORDING);
...
}
void CameraCilent::stopRecording(){
...
mCameraService->playSound(CameraService::SOUND_RECORDING);
...
}
因此,framework/base/core/java/android/hardware/Camera中的enableShutterSound对Recording没有作用,因此我们只需加入与拍照时的同等逻辑,即:
status_t CameraCilent::startRecordingMode(){
...
if (mPlayShutterSound) {
mCameraService->playSound(CameraService::SOUND_RECORDING);
}
...
}
void CameraCilent::stopRecording(){
...
if (mPlayShutterSound) {
mCameraService->playSound(CameraService::SOUND_RECORDING);
}
...
}
这样我们就可以直接在上层调用android.hardware.Camera中的enableShutterSound来控制拍照和录制模式的shutter sound.
下面实现app层的逻辑,正如我前面所说的那样,4.2的改动很大,不过改动起来还是很方便的。
在UI方面,因为要在CameraSettings中添加一个开关,则需要做如下操作:
packages/apps/Camera/src/com/android/camera/SettingsChecker.java
...
public static final int ROW_SETTING_SHUTTER_SOUND = 51;
...
public static final int[] SETTING_GROUP_COMMON_FOR_TAB_MY_SETTING = new int[]{
...
ROW_SETTING_SHUTTER_SOUND;
...
}
public static final int[] SETTING_GROUP_COMMON_FOR_TAB = new int[]{
...
ROW_SETTING_SHUTTER_SOUND;
...
}
public static final int[] SETTING_GROUP_CAMERA_FOR_PARAMETERS = new int[]{
...
ROW_SETTING_SHUTTER_SOUND;
...
}
public static final int[] SETTING_GROUP_VIDEO_FOR_PARAMETERS = new int[]{
...
ROW_SETTING_SHUTTER_SOUND;
...
}
public static final int[] SETTING_GROUP_ALL_IN_SETTING = new int[]{
...
ROW_SETTING_SHUTTER_SOUND;
...
}
static {
...
MATRIX_MODE_STATE[ROW_SETTING_SHUTTER_SOUND] = new int[]{STATE_EO,STATE_EO,STATE_EO,STATE_EO,STATE_EO,STATE_EO,STATE_EO,STATE_EO,STATE_EO,STATE_EO,STATE_EO,STATE_EO,STATE_EO};
...
RESET_STATE_VALUE[ROW_SETTING_SHUTTER_SOUND] = new String[]{"on"};
...
KEYS_FOR_SETTING[ROW_SETTING_SHUTTER_SOUND] = CameraSettings.KEY_SOUND;
...
MATRIX_SETTING_VISIBLE[CAMERA_BACK_ID][ROW_SETTING_SHUTTER_SOUND] = true;
...
MATRIX_SETTING_VISIBLE[CAMERA_FRONT_ID][ROW_SETTING_SHUTTER_SOUND] = true;
...
DEFAULT_VALUE_FOR_SETTING_ID[ROW_SETTING_SHUTTER_SOUND] = R.string.pref_camera_shuttersound_default;
...
}
private static String getParameterValue(Parameters parameters, int row) {
...
case ROW_SETTING_SHUTTER_SOUND:
throw new CameraSettingsException("Cannot get sound from parameters");
...
}
private static boolean setParameterValue(Context context, Parameters parameters, int row, String Value) {
...
case ROW_SETTING_SHUTTER_SOUND:
updateShutterSound(context);
break;
...
}
private static boolean isParamenterSupportedValue(Paramenters parameters, int row, String value) {
...
case ROW_SETTING_SHUTTER_SOUND:
support = true;
break;
...
}
private static void updateShutterSound(Context context) {
Camera camera = (Camera) context;
camera.updateShutterSound();
}
packages/apps/Camera/src/com/android/camera/Camera.java
public static final int MSG_SHUTTER_SOUND_KEY = 24;
...
public void updateShutterSound() {
mMainHandler.sendEmptyMessage(MSG_SHUTTER_SOUND_KEY);
}
...
public Handler mMainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
...
case MSG_SHUTTER_SOUND_KEY:
if ("on".equals(mSettingChecker.getStringCurrentValue(SettingChecker.ROW_SETTING_SHUTTER_SOUND))) {
mCameraActor.enableShutterSound(true);
} else {
mCameraActor.enableShutterSound(false);
}
...
}
}
public void enableShutterSound(boolean enable) {
mCameraDevice.enableShutterSound(enable);
}
packages/apps/Camera/src/com/android/camera/CameraManager.java
private static final int SET_SHUTTER_SOUND = 118;
public void enableShutterSound(boolean enable) {
mSig.close();
mCameraHandler.obtainMessage(SET_SHUTTER_SOUND,enable).sendToTarget();
mSig.block();
}
private class CameraHandler extends Handler {
...
@Override
public void handleMessage(final Message msg) {
...
case SET_SHUTTER_SOUND:
mCamera.enableShutterSound((Boolean)msg.obj);
break;
...
}
...
}
packages/apps/Camera/src/com/mediatek/camera/ICamera.java
public interface ICamera {
...
public void enableShutterSound(boolean enable);
...
}
packages/apps/Camera/src/com/mediatek/camera/AndroidCamera.java
...
import android.hardware.Camera;
...
public class AndroidCamera implements ICamera {
...
protect Camera mCamera;
...
public void enableShutterSound(boolean enable) {
mCamera.enableShutterSound(enable);
}
...
}
packages/apps/Camera/src/com/android/camera/actor/CameraActor.java
public void enableShutterSound(boolean enable) {
mContext.enableShutterSound(enable);
}
从上面代码可以看出,AndroidCamera.java中的enableShutterSound方法调用了framework层android.hardware.Camera.enableShutterSound;而在Camera中,
case MSG_SHUTTER_SOUND_KEY:
if ("on".equals(mSettingChecker.getStringCurrentValue(SettingChecker.ROW_SETTING_SHUTTER_SOUND))) {
mCameraActor.enableShutterSound(true);
} else {
mCameraActor.enableShutterSound(false);
}
在这里,只需简单的调用mCameraActor.enableShutterSound即可,而其他的Actor都是继承自CameraActor,也就是说,我们只需加上上述代码,其他各种模式的shutter sound 我们都可以控制了。其可扩展性确实挺高的,但是容易让人绕晕。