最近有一个客户有这样的需求:
1、在【设置】--->【无障碍】中添加一个开关按钮。
如果打开开关的话,双击某个物理按键的时候,打开闪光灯,再双击该物理按键的时候,关闭闪光灯。
如果关闭开关的话,双击该物理按键的时候,不做任何处理。
2、打开关闭闪光灯的状态,在下拉菜单中也要同步。
如下图所示的效果:
当打开上面添加的开关后,如果双击POC键(POC键是我们公司自定义的一个物理按键)的时候,就打开闪光灯,并将下拉菜单中的闪光灯图标点亮,如下图所示
如果再次双击POC键(POC键是我们公司自定义的一个物理按键)的时候,就关闭闪光灯,并将下拉菜单中的闪光灯图标熄灭,如下图所示
====================================================================================================================================
下面来具体说说怎么实现该功能:
第一步:添加开关按钮布局
在packages/apps/Settings/res/xml/accessibility_settings.xml 文件中添加一个开关,开关位置放在【按电源按钮结束通话】和【自动选择屏幕】中间,代码如下
<SwitchPreference android:key="toggle_power_button_ends_call_preference" android:title="@string/accessibility_power_button_ends_call_prerefence_title" android:persistent="false"/> <!-- added by ouyang start [2015-11-3] --> <SwitchPreference android:key="toggle_camera_button__start_flashlight_preference" android:title="@string/accessibility_camera_button_start_flashlight_preference_title" android:summary="@string/accessibility_camera_button_start_flashlight_preference_subtitle" android:persistent="false"/> <!-- added by ouyang end [2015-11-3] --> <SwitchPreference android:key="toggle_lock_screen_rotation_preference" android:title="@string/accelerometer_title" android:persistent="false"/>
在packages/apps/Settings/res/values-zh-rCN/strings.xml文件中添加相应的字符串
<!-- added by ouyang start [2015-11-3] --> <string name="accessibility_camera_button_start_flashlight_preference_title">"双击[相机键]打开闪光灯"</string> <string name="accessibility_camera_button_start_flashlight_preference_title_E580">"双击[POC键]打开闪光灯"</string> <string name="accessibility_camera_button_start_flashlight_preference_subtitle">"开启此功能后,摄像机暂时无法使用"</string> <!-- added by ouyang end [2015-11-3] -->
packages/apps/Settings/res/values/strings.xml文件中添加相应的字符串
<!-- added by ouyang start [2015-11-3] --> <string name="accessibility_camera_button_start_flashlight_preference_title">"Camera button twice,open flash light"</string> <string name="accessibility_camera_button_start_flashlight_preference_title_E580">"POC button twice,open flash light"</string> <string name="accessibility_camera_button_start_flashlight_preference_subtitle">"After open this feature, the camera can not be used"</string> <!-- added by ouyang end [2015-11-3] -->
第二步:对该开关按钮做逻辑处理,在packages/apps/Settings/src/com/android/settings/accessibility/AccessibilitySettings.java文件中
先定义一个字符串常量,该常量为添加的开关的key,定义该按钮开关常量和SharedPreences常量,用来保存该按钮打开关闭状态值
// added by ouyang start [2015-11-3] private static final String TOGGLE_CAMER_BUTTON_START_FLASHLIGHT_PREFERENCE = "toggle_camera_button__start_flashlight_preference"; // added by ouyang end [2015-11-3]
// added by ouyang start [2015-11-3] private SwitchPreference mToggleCameraButtonStartFlashlightPreference; private SharedPreferences preferences; private SharedPreferences.Editor editor; // added by ouyang end [2015-11-3]
通过该字符串找到定义的开关,并做些处理,如从保存好的Perference中读取开关打开关闭状态并显示,在initializeAllPreferences方法中,添加如下代码
// added by ouyang start [2015-11-3] mToggleCameraButtonStartFlashlightPreference = (SwitchPreference) findPreference(TOGGLE_CAMER_BUTTON_START_FLASHLIGHT_PREFERENCE); if (android.os.SystemProperties.isHanbangVersion()) { Log.e(TAG, "is HanbangVersion()"); mToggleCameraButtonStartFlashlightPreference.setEnabled(false); }else{ Log.e(TAG, "is not HanbangVersion()"); mToggleCameraButtonStartFlashlightPreference.setEnabled(true); } Log.e(TAG, "mToggleCameraButtonStartFlashlightPreference.isEbable="+ mToggleCameraButtonStartFlashlightPreference.isEnabled()); if (android.os.SystemProperties.isDT800Project()) { mToggleCameraButtonStartFlashlightPreference.setTitle(R.string.accessibility_camera_button_start_flashlight_preference_title); }else if (android.os.SystemProperties.isE580Project()) { mToggleCameraButtonStartFlashlightPreference.setTitle(R.string.accessibility_camera_button_start_flashlight_preference_title_E580); } preferences= getActivity().getApplicationContext().getSharedPreferences("FlashLight", Context.MODE_MULTI_PROCESS +Context.MODE_WORLD_READABLE +Context.MODE_WORLD_WRITEABLE); editor=preferences.edit(); boolean flashChecked=preferences.getBoolean("flashChecked", false); mToggleCameraButtonStartFlashlightPreference.setChecked(flashChecked); Log.e(TAG, "flashChecked="+flashChecked); // added by ouyang end [2015-11-3]
这段代码主要是对该开关进行初始化,并对不同的项目进行判断,DT800项目和E580项目加载不同的字符串来描述开关。这些方法可以在/frameworks/base/core/java/android/os/SystemProperties.java文件中自己添加,代码如下:
public static boolean isDT800Project() { return SystemProperties.get("ro.custom.build.version").contains("DT800"); } public static boolean isE580Project() { return SystemProperties.get("ro.custom.build.version").contains("E580"); } public static boolean isHanbangVersion(){ return SystemProperties.get("ro.product.model").contains("Hanbang"); }
在packages/apps/Settings/src/com/android/settings/accessibility/AccessibilitySettings.java文件中的onPreferenceTreeClick方法中,要添加对该开关的点击事件处理。
代码如下,添加几行代码:
else if (mTogglePowerButtonEndsCallPreference == preference) { handleTogglePowerButtonEndsCallPreferenceClick(); return true; } // added by ouyang start [2015-11-3] else if (mToggleCameraButtonStartFlashlightPreference == preference) { handleToggleCameraButtonStartFlashlightPreferenceClick(); return true; } // added by ouyang end [2015-11-3] else if (mToggleLockScreenRotationPreference == preference) { handleLockScreenRotationPreferenceClick(); return true; }
其中handleToggleCameraButtonStartFlashlightPreferenceClick()方法自己自定义的,代码如下:
// added by ouyang start [2015-11-3] private void handleToggleCameraButtonStartFlashlightPreferenceClick(){ if (mToggleCameraButtonStartFlashlightPreference.isChecked()) { editor.putBoolean("flashChecked", true); editor.commit(); }else{ editor.putBoolean("flashChecked", false); editor.commit(); } } // added by ouyang end [2015-11-3]
该方法主要功能是保存该开关是打开状态还是关闭状态,这个状态值可以让其他的进程读取。
第三步:定义一个BroadcastReceiver,并动态注册该广播。代码文件在frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
,在该文件中添加一个BroadcastReceiver
//added by ouyang private final BroadcastReceiver mFlashBroadcastReceiver =new BroadcastReceiver(){ boolean isDoublePress = false; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Log.d(TAG, "action= " + action); Log.d(TAG, "isDoublePress= " + isDoublePress); Log.d(TAG, "now time = " + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(new Date())); if ((action == "com.runbo.camera.key.up") || (action == "com.runbo.poc.key.up")) { Handler checkHandler = new Handler(); if (!isDoublePress) { isDoublePress = true; Log.i(TAG, "<----===============Single Press the Camera Key---->"); Runnable CheckDoubleRunnable = new Runnable() { @Override public void run() { isDoublePress = false; } }; checkHandler.postDelayed(CheckDoubleRunnable, 500); } else { isDoublePress = false; Log.i(TAG, "<----============Double Press the Camera Key ---->"); boolean handlerReceiver = false; boolean flashChecked=false; try { Context myContext= context.createPackageContext("com.android.settings", Context.CONTEXT_IGNORE_SECURITY); SharedPreferences sharedPreferences = myContext.getSharedPreferences("FlashLight", Context.MODE_WORLD_READABLE | Context.MODE_MULTI_PROCESS); flashChecked = sharedPreferences.getBoolean("flashChecked", false); } catch (Exception e) { Log.d(TAG, Log.getStackTraceString(e)); } if (action == "com.runbo.camera.key.up") { if (android.os.SystemProperties.isDT800Project() && !android.os.SystemProperties.isHanbangVersion()) { handlerReceiver = true; } } else if (action == "com.runbo.poc.key.up") { if (android.os.SystemProperties.isE580Project()) { handlerReceiver = true; } } Log.d(TAG, "handlerReceiver= " + handlerReceiver); Log.d(TAG, "flashChecked= " + flashChecked); if (handlerReceiver && flashChecked) { Log.i(TAG, "============mState.value="+mState.value); if (!mState.value) { boolean newState = !mState.value; mFlashlightController.setFlashlight(newState); refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE); Log.i(TAG, "============setFlashlight(true);============"); }else{ boolean newState = !mState.value; mFlashlightController.setFlashlight(newState); refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE); Log.i(TAG, "============setFlashlight(false);============"); } } } } } };
在FlashlightTile的构造方法中进行注册,代码如下:
public FlashlightTile(Host host) { super(host); mFlashlightController = host.getFlashlightController(); mFlashlightController.addListener(this); //added by ouyang start IntentFilter pocFilter = new IntentFilter(); pocFilter.addAction("com.runbo.poc.key.up"); pocFilter.addAction("com.runbo.camera.key.up"); this.mContext.registerReceiver(mFlashBroadcastReceiver, pocFilter); Log.d(TAG, "registerReceiver(mFlashBroadcastReceiver, pocFilter)"); //added by ouyang end }
该BroadcastReceiver接收通过按POC键后释放而发送的广播“com.runbo.poc.key.up”和通过按Camera键后释放而发送的广播“com.runbo.camera.key.up”,这两个广播是自定义的广播。然后判断是单击还是双击,当双击后再通过读取SharedPreferences的值来判断定义的开关是否是打开的,如果开关是打开的再判断闪光灯是打开还是关闭,如果是打开的,双击后就关闭闪光灯。如果是关闭的,就打开闪光灯。并更新下拉菜单的图标和相应的状态。如果开关是关闭的,不进行打开关闭闪光灯的操作。
这两个广播是在frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java文件中的interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)方法中额外添加的代码,发送广播出来的。
作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:http://blog.csdn.net/ouyang_peng
====================================================================================