一键拍照,一键录像:
(S版本)
首先在对应的键值逻辑上做逻辑处理
base/services/core/java/com/android/server/policy/PhoneWindowManager.java
case KeyEvent.KEYCODE_CAMERA:{// take photo
if (down) {
if(getCurrentActivityName().equals("com.freeme.factory.input.KeyboardTest")){
break;
} else if(!getCurrentActivityName().contains("com.mediatek.camera")) {
Intent intent;
if (keyguardActive) {
//intent = newIntent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
intent = newIntent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE);
intent.putExtra("takePhoto","1");
} else {
//intent = newIntent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
intent = newIntent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra("takePhoto","1");
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivityAsUser(intent,UserHandle.CURRENT_OR_SELF);
}
}
break;
}
case KeyEvent.KEYCODE_F3:{//yantao takevideo
if (down) {
if(getCurrentActivityName().equals("com.freeme.factory.input.KeyboardTest")){
break;
} else if (!getCurrentActivityName().contains("com.mediatek.camera")){
Intent intent = newIntent(MediaStore.ACTION_VIDEO_CAPTURE);
intent.putExtra("takeVideo","1");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivityAsUser(intent,UserHandle.CURRENT_OR_SELF);
}
}
break;
}
private String getCurrentActivityName() {
ActivityManager am = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> taskInfo =am.getRunningTasks(1);
ComponentName componentInfo = taskInfo.get(0).topActivity;
android.util.Log.i("yantao","currentActivity name=="+componentInfo.getClassName());
return componentInfo.getClassName();
}
然后在相机应用里改
vendor/mediatek/proprietary/packages/apps/Camera2/host/src/com/mediatek/camera/CameraActivity.java
private staticfinal int DELAY_MSG_ONE_CLICK_CAMERA_FLAG = 100;
在protected voidonResumeTasks() {最后添加
Intent intent =getIntent();
String takeVideo=intent.getStringExtra("takeVideo");
String takePhoto=intent.getStringExtra("takePhoto");
if(takeVideo != null || takePhoto !=null){
if("1".equals(takeVideo) ||"1".equals(takePhoto))
mMainHandler.sendEmptyMessageDelayed(DELAY_MSG_ONE_CLICK_CAMERA_FLAG,500);
}
在privateHandler mMainHandler = new Handler() {
加入case
case DELAY_MSG_ONE_CLICK_CAMERA_FLAG:
mCameraAppUI.triggerShutterButtonClick(-1);
break;
这里的调起的不是相机本身这个应用,是里面单独的activity,所以加flag不让显示在后台Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS,这样用户就只能点击按键才能进入。
这样有个bug:锁屏的时候点击一键相机会跳到相机默认界面然后拍照,而视频的那个界面一键按不出来,等解锁之后才显示这个video界面但是没有录制
注意!!!!!这个delay做的延迟如果太短的话,界面ui没起来就不会有功能,比如说下面的老版本如果用0,5秒的话功能会有问题,用1秒就正常
(O版本为例)
O版本需要改动cameraactivity里面的逻辑,因为没有triggerShutterButtonClick,这个方法了,需要用到photo和video分别的click方法
还是在src/com/android/camera/CameraActivity.java
private staticfinal int DELAY_MSG_ONE_CLICK_PHOTO_FLAG = 100;
private static final intDELAY_MSG_ONE_CLICK_VIDEO_FLAG = 200;
Intent intent =getIntent();
String takeVideo=intent.getStringExtra("takeVideo");
String takePhoto=intent.getStringExtra("takePhoto");
android.util.Log.i("yantao","takeVideo=="+takeVideo+"\ntakePhoto=="+takePhoto);
if(takeVideo != null || takePhoto !=null){
if("1".equals(takeVideo) && takePhoto == null){
android.util.Log.i("yantao","cameraactivitytakeing");
mMainHandler.sendEmptyMessageDelayed(DELAY_MSG_ONE_CLICK_VIDEO_FLAG,1000);
}
if(takeVideo == null &&"1".equals(takePhoto)){
android.util.Log.i("yantao","cameraactivitytakeing");
mMainHandler.sendEmptyMessageDelayed(DELAY_MSG_ONE_CLICK_PHOTO_FLAG,1000);
}
}
case DELAY_MSG_ONE_CLICK_PHOTO_FLAG:
mModuleManager.onPhotoShutterButtonClick();
break;
case DELAY_MSG_ONE_CLICK_VIDEO_FLAG:
mModuleManager.onVideoShutterButtonClick();
break;
注意!!!
如果要满足拍完照或者录完像自动退出的需求,修改如下:
大致和上面一样。需要再加一个handler,因为点击ok键保存图片也需要时间等ui,
private HandlermHandler;
在resume里实例
mHandler = newHandler();
最后在caseDELAY_MSG_ONE_CLICK_PHOTO_FLAG:
加入一个
mHandler.postDelayed(newRunnable() {
public void run() {
mModuleManager.onOkButtonPress();
}
}, 1000);
一键录像,再按一次按键就停止录像然后保存退出:
Cameraactivity的都一样不需要改,另外需要在对应的快门处理上加一个按键逻辑
比如O版本的在
src/com/mediatek/camera/mode/VideoMode.java
protectedboolean onKeyDown(int keyCode, KeyEvent event) {
加入,这个F4就是我们一键录像的物理按键,
caseKeyEvent.KEYCODE_F4:
onBackPressed();
mActivity.finish();
break;
这个返回操作是由于源码就设计好了,返回就能保存,调用这个方法就行
protectedboolean onBackPressed() {
Log.d(TAG, "[onBackPressed()]CurrentModeState " + getModeState());
if (ModeState.STATE_IDLE ==getModeState()) {
return false;
}
if (ModeState.STATE_RECORDING ==getModeState()) {
stopVideoRecordingAsync(true);
}
return true;
}
保存完之后还是会回到那个×或√的选项,但此时其实已经保存了,所以只需要最后在finish掉
一键录音:
base/services/core/java/com/android/server/policy/PhoneWindowManager.java
按键处理:
case KeyEvent.KEYCODE_F2:{ //yantao record
if(getTopActivityPacakgeName().equals("com.freeme.factory")
||getCurrentActivityName().contains("com.android.soundrecorder")) {
break;
}
if (down) {
Intent intent = new Intent();
intent.setClassName("com.android.soundrecorder","com.android.soundrecorder.SoundRecorder");
intent.putExtra("takeRecord","1");
SystemProperties.set("persist.sys.record.taking","1");
startActivityAsUser(intent,UserHandle.CURRENT_OR_SELF);
}else if (event.getAction() ==KeyEvent.ACTION_UP) {
}
break;
}
这里加入属性persist.sys.record.taking,是为了判断每次按键进入的录音机才有录音功能,如果从recent后台进入的话还是之前的activity,不判断的话依然会有功能。
这里用了源码自带的录音机S版本为例:
vendor/mediatek/proprietary/operator/packages/apps/SoundRecorder/OP01/src/com/android/soundrecorder/SoundRecorder.java
private staticfinal int DELAY_MSG_ONE_CLICK_RECORD_FLAG = 100;
在protected void onResume() {最后添加
Intent intent =getIntent();
if(android.os.SystemProperties.get("persist.sys.record.taking","0").equals("1")){
String takeRecord=intent.getStringExtra("takeRecord");
if(takeRecord != null){
if(takeRecord.equals("1")){
android.util.Log.i("yantao","takeRecordin");
mHandler.sendEmptyMessageDelayed(DELAY_MSG_ONE_CLICK_RECORD_FLAG,100);
android.os.SystemProperties.set("persist.sys.record.taking","0");
}
}
}
在handler处理
private HandlermHandler = new Handler() {
添加case
case DELAY_MSG_ONE_CLICK_RECORD_FLAG:
onClickRecordButton();
break;
注意!!!
不能直接使用点击事件,不然无法成功!!!需要handler做异步处理,
避免直接在UI主线程中处理事务导致影响UI主线程的其他处理工作。那这个录音机为例,如果直接做点击事件的话,那个mService就是空,说明主线程还没准备好,原本是正常的。所以需要用handler做异步处理,这里的延时其实也可以不要直接sendEmptyMessage
sendMessage(Messagemsg)
sendEmptyMessage(int what)
其实这两个方法是一样一样的,一个传Message类型的msg,一个传int类型的what,传what的,最终会转为msg
Handler基本用法:
import android.os.Handler;
mHandler.sendEmptyMessageDelayed(int,100);
private HandlermHandler = new Handler() {
@Override
public void handleMessage(Message msg){
switch(msg.what) {
case int:
break;
default:
break;
}
}
};
想要移除该消息
mHandler.removeMessages(int);
handler.removeMessages(0);是配合
mHandler.postDelayed(new Runnable() {
public void run() {
}
},1000);
整个handler做延时处理,handler.removeMessages(0);就把post操作取消了
MediaStore.ACTION_IMAGE_CAPTURE,MediaStore.ACTION_IMAGE_CAPTURE_SECURE
只是单纯拍照,跳转的界面不能录像,且拍一张就退出了
MediaStore.ACTION_VIDEO_CAPTURE,也是只能录像
MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA和MediaStore.ACTION_IMAGE_CAPTURE_SECURE是直接进入相机
Intent.FLAG_ACTIVITY_NEW_TASK
在Activity上下文之外启动Activity需要给Intent设置FLAG_ACTIVITY_NEW_TASK标志,不然会报异常。
.加了该标志,如果在同一个应用中进行Activity跳转,不会创建新的Task,只有在不同的应用中跳转才会创建新的Task
Intent..FLAG_ACTIVITY_CLEAR_TOP
销毁目标Activity和它之上的所有Activity,重新创建目标Activity
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
如果设置,新的Activity不会在最近启动的Activity的列表中保存。J就是recent里面看不到后台,但实际上还是有的,不过过一会会被清掉
- Intent.FLAG_ACTIVITY_SINGLE_TOP
- 与加载模式singleTop功能相同
- 栈顶复用(当被启动的Activity处于Task栈顶时,可以复用,直接调用onNewIntent方法)
一般用组合
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP)
设置了singleTop、singleTask、singleInstance这三种模式的Activity,如果开启一个新的Activity页面,栈顶存在相同的实例就复用,都不会重新创建一个新实例,Activity复用后都会调用onNewIntent(Intent intent)方法。
intent.setFlags是替换原来的flag,addFlags是原有基础上添加flag