前言

客户要求给 Camera 做一个 指纹拍照功能,也就是在Camera 界面,点击后置指纹模组时,Camera 能拍摄相片和视频。

工作

在处理指纹拍照时,就需要指纹模组厂商来协助处理,上层只需要做 KeyCode 获取指纹模组的点击事件;其二就是在 Camera 应用中添加相应的点击事件。

这里以上层的 keycode 是286,底层的keycode是 252为例。

添加 指纹keyEvent

Generic.kl 中添加 上报的 KEYHALL_FPCAMERA,其对应的键值为 252

--frameworks

base/data/keyboards/Generic.kl

@@ -247,6 +247,10 @@ key 224 BRIGHTNESS_DOWN

key 225 BRIGHTNESS_UP

key 226 HEADSETHOOK

+key 252 FPCAMERA

在InputEventLabels.h 添加键值映射。

-- frameworks

/native/include/input/InputEventLabels.h

@@ -325,6 +325,9 @@ static const InputEventLabel KEYCODES[] = {

DEFINE_KEYCODE(SYSTEM_NAVIGATION_RIGHT),

DEFINE_KEYCODE(ALL_APPS),

DEFINE_KEYCODE(REFRESH),

+ DEFINE_KEYCODE(FPCAMERA),

{ NULL, 0 }

};

在 keycodes 添加键值

-- frameworks

native/include/android/keycodes.h

@@ -769,7 +769,11 @@ enum {

/** all apps */

AKEYCODE_ALL_APPS = 284,

/** refresh key */

AKEYCODE_REFRESH = 285

+ AKEYCODE_FPCAMERA = 286,

在 /current.txt 中添加键值

-- frameworks

base/api/current.txt

@@ -46932,6 +46932,7 @@ package android.view {

field public static final int KEYCODE_GRAVE = 68; // 0x44

field public static final int KEYCODE_GUIDE = 172; // 0xac

field public static final int KEYCODE_H = 36; // 0x24

+ field public static final int KEYCODE_FPCAMERA = 286; //

field public static final int KEYCODE_HEADSETHOOK = 79; // 0x4f

field public static final int KEYCODE_HELP = 259; // 0x103

field public static final int KEYCODE_HENKAN = 214; // 0xd6

在 KeyEvent 添加键值关系。

-- frameworks

/base/core/java/android/view/KeyEvent.java

@@ -808,8 +808,9 @@ public class KeyEvent extends InputEvent implements Parcelable {

public static final int KEYCODE_ALL_APPS = 284;

/** Key code constant: Refresh key. */

public static final int KEYCODE_REFRESH = 285;

+ public static final int KEYCODE_FPCAMERA = 286;

- private static final int LAST_KEYCODE = KEYCODE_REFRESH;

+ private static final int LAST_KEYCODE = KEYCODE_FPCAMERA;

// NOTE: If you add a new keycode here you must also add it to:

// isSystem()

@@ -1861,6 +1862,7 @@ public class KeyEvent extends InputEvent implements Parcelable {

case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN:

case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT:

case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT:

+ case KeyEvent.KEYCODE_FPCAMERA:

return true;

}

@@ -1877,6 +1879,7 @@ public class KeyEvent extends InputEvent implements Parcelable {

case KeyEvent.KEYCODE_STEM_1:

case KeyEvent.KEYCODE_STEM_2:

case KeyEvent.KEYCODE_STEM_3:

+ case KeyEvent.KEYCODE_FPCAMERA:

return true;

}

return false;

如果需要验证是否添加成功可以在 PhoneWindowManager 中进行处理。

-- framworks

base/services/core/java/com/android/server/policy/PhoneWindowManager.java

@@ -6543,6 +6543,11 @@ public class PhoneWindowManager extends AbsPhoneWindowManager implements WindowM

break;

}

+ case KeyEvent.KEYCODE_FPCAMERA: {

+ android.util.Log.d("xxx","FPCAMERA is ok");

+ break;

+ }

+

case KeyEvent.KEYCODE_SLEEP: {

result &= ~ACTION_PASS_TO_USER;

isWakeKey = false;

验证方式:

adb shell input keyevent 286

操作,查看 log 日志

在确定 log 中出现 “FPCAMERA is ok”,就再进行下一步操作。

Camera 拍照操作。

为了保证指纹拍照这个事件不会在其他应用中被滥用。寄可以考虑当 Camera 启动时设置一个属性,那么Camera可以启动指纹拍照,如果Camera退出,那么依据这个属性可以保证指纹拍照不在其它应用中被滥用从底层获取消息。

应用启动,肯定经过这六个过程。

from:


Android keystore2 源码解读_android

如果在 onCreate 或 onStart 中开启属性,在 onStop 或 onDestroy 中关闭属性,但是应用只是暂时的推到后台或任何可见状态执行了onStop之后。再次进入Camera时,属性值依然为关。如果一个应用要正常的执行,肯定会执行 onResume和onPause,所以可以考虑在这两个方法中添加属性开关。

如果一个应用执行了 onCreate,其必会执行 onDestroy;如果执行了 onStart,那么其必须执行onStop;如果执行了 onResume,其必会执行onPause。但是它们之间的其他步骤可能就不会执行了。

-- QuickActivity

@@ -129,6 +132,10 @@ public abstract class QuickActivity extends Activity {

@Override

protected final void onResume() {

logLifecycle("onResume", true);

+ SystemProperties.set("sys.fp_camshot.enable","true");

// For lockscreen launch, there are two possible flows:

// 1. onPause() does not occur before mOnResumeTasks is executed:

@@ -172,6 +179,11 @@ public abstract class QuickActivity extends Activity {

}

super.onPause();

mStartupOnCreate = false;

+ SystemProperties.set("sys.fp_camshot.enable","false");

当然,sys.fp_camshot.enable 与底层做了相似的处理,这个需要相应的元件厂商来处理。同时,这里还有一个问题,就是如果修改这个属性,会导致Camera启动时崩溃。同时平台应用没法设置系统属性值,这个无论如何都会发生 Camera 异常。所以如果是测试验证的话,出现了设置属性不能 “set” 或 “get”, 那么可以采用

adb shell setenforce 0

adb shell getenforce

来暂时授予权限来调试,当然如果需要彻底解决权限问题,还需要比较复杂的处理。现在先解决 Camera 的拍照问题。

因为不同项目对Camera代码是不同的,所以之后的代码就不写了。只要加上KeyEvent.KEYCODE_FPCAMERA:

在对应的位置加上这个 keycode,既可以控制了。

当然,如果放任指纹模组在任何时候都可以触发,那么可以不加这个属性,让指纹模组在任何时候都可以获取触发事件。虽然会对手机的性能造成一定的影响。

现在来处理权限问题,由于不能在 Camera 应用中采用 SystemProperties.set 这个方法来处理,那么思考下:比如,每次 Camera 打开时,必然会需要预览操作。

那么可以可以考虑在frameworks 中的Camera 预览操作进行权限的处理。通过 Log 验证,手机预览时会执行 av/services/camera/libcameraservice/device3/Camera3Device.cpp。

预览:

status_t Camera3Device::RequestThread::setRepeatingRequests(

const RequestList &requests,

/*out*/

int64_t *lastFrameNumber) {

ATRACE_CALL();

Mutex::Autolock l(mRequestLock);

property_set("sys.fp_camshot.enable", "true");

...

结束预览

status_t Camera3Device::disconnect() {

ATRACE_CALL();

Mutex::Autolock il(mInterfaceLock);

ALOGI("%s: E", __FUNCTION__);

property_set("sys.fp_camshot.enable", "false");

...

处理权限

在 device 目录下:

---------------- sprd/pike2/common/sepolicy/cameraserver.te ------------------

typeattribute cameraserver system_writes_vendor_properties_violators;

set_prop(cameraserver, vendor_sys_prop)

----------------- sprd/pike2/common/sepolicy/property_contexts -----------------

sys.fp_camshot.enable u:object_r:vendor_sys_prop:s0

这样就保证了刚才的 Camera3Device.cpp 设置的属性的权限了。

当然,在指纹模组中如果需要获取这个属性,其也需要权限,但这是由驱动来处理的,所以不表。

基本上,这个问题就这样,可以验证成功了。