├── .classpath
├── .gitignore
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── Android.mk
├── AndroidManifest.xml
├── README.md
├── apk
├── Bluetooth.apk
├── TestKey.apk
├── device-2015-01-21-152934.png
├── device-2015-02-07-105356.png
├── device-2015-02-07-105501.png
├── device-2015-02-07-121646.png
└── last_number_redail.png
├── gen
└── com
│ └── example
│ └── testkey
│ ├── BuildConfig.java
│ └── R.java
├── ic_launcher-web.png
├── libs
└── android-support-v4.jar
├── proguard-project.txt
├── project.properties
├── res
├── drawable-hdpi
│ └── ic_launcher.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-xhdpi
│ └── ic_launcher.png
├── drawable-xxhdpi
│ └── ic_launcher.png
├── layout
│ └── activity_main.xml
├── menu
│ └── main.xml
├── raw
│ ├── lapple.mp3
│ └── silence10sec.mp3
├── values-sw600dp
│ └── dimens.xml
├── values-sw720dp-land
│ └── dimens.xml
├── values-v11
│ └── styles.xml
├── values-v14
│ └── styles.xml
└── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
└── src
└── com
└── example
└── testkey
├── KeyService.java
├── MainActivity.java
└── MusicIntentReceiver.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | !TestKey.apk
4 | !Bluetooth.apk
5 | *.ap_
6 |
7 | # Files for the Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 |
17 | # Gradle files
18 | .gradle/
19 | build/
20 |
21 | # Local configuration file (sdk path, etc)
22 | local.properties
23 |
24 | # Proguard folder generated by Eclipse
25 | proguard/
26 |
27 | # Log Files
28 | *.log
29 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | TestKey
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH:= $(call my-dir)
2 |
3 | include $(CLEAR_VARS)
4 |
5 | LOCAL_MODULE_TAGS := optional
6 |
7 | LOCAL_SRC_FILES := $(call all-java-files-under, src)
8 |
9 | LOCAL_PACKAGE_NAME := TestKey
10 |
11 | LOCAL_CERTIFICATE := platform
12 |
13 | include $(BUILD_PACKAGE)
14 |
15 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
23 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Android按键测试程序
2 | ---
3 | ### 物理按键测试
4 | 正常安装启动后就可以检测
5 |
6 | ### 蓝牙耳机播放音乐相关按键测试
7 | 需要额外播放音乐才能监听
8 |
9 | ### 蓝牙耳机语音通话相关按键测试
10 | 其中:
11 |
12 | VOICE_COMMAND : 语音拨号键
13 | LAST_NUMBER_REDIAL : 末位重拨
14 | ... : ...
15 |
16 | 说明:
17 |
18 | VOICE_COMMAND 正常安装后就可以监听到
19 | LAST_NUMBER_REDIAL 需要将该APP放置到system/app目录下放可正常监听到
20 | 比如,当LAST_NUMBER_REDIAL被触发后会出现PHONE应用和TESTKEY争抢启动。
21 | 
22 |
23 | 监听到 末位重拨 按键:
24 | 
25 |
26 |
27 | ### 20150122更
28 | 介于国产手机ROM进行了CALL_PRIVILEGED进行了恶意屏蔽导致无法正常使用,所以只有通过更改Bluetooth.apk对「末号重拨」进行重定向。
29 |
30 | apk/目录下TestKey.apk/Bluetooth.apk是最新的。
31 |
32 | 替换系统自带Bluetooth.apk后,这次正常方式安装TestKey.apk就可以了。
33 |
34 | 正常现象是:当按下「末号重拨」键时,不再进行「末号重拨」,而是调起TestKey.apk.
35 |
36 | 如果实验正常,那么下一步就是转向到「语音拨号」。
37 |
38 | ### 20150123更 重定向
39 | 1.不再监听VOICE_COMMAND且将LAST_NUMBER_REDIAL重定向到VOICE_COMMAND
40 |
41 | 只更新了TestKey.apk只重新安装它就好。
42 |
43 | 另:如果你的手机支持VOICE_COMMAND(语音拨号)时直接从睡眠(黑屏)中唤醒,那么就能唤醒。
44 |
45 | TestKey.apk目前只启动重定向的功能。
46 |
47 | 2.重定向后自行关闭
48 |
49 | ### 20150124更 选择性重定向
50 | 添加判断条件,当且仅当在BT连接/黑屏(锁屏)状态下进行重定向。
51 |
52 | 下午:更新源码,解决逻辑错误,已经测试。
53 |
54 | ### 20150205更 添加连接蓝牙后自动将黑屏时间设置为10秒
55 |
56 | ### 20150207更 添加连接蓝牙休眠时间设置为10秒断开设置为120秒
57 | 并添加了通知,在Miui中验证过了。
58 |
59 | 
60 |
61 | 
62 |
63 | 
64 |
--------------------------------------------------------------------------------
/apk/Bluetooth.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/apk/Bluetooth.apk
--------------------------------------------------------------------------------
/apk/TestKey.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/apk/TestKey.apk
--------------------------------------------------------------------------------
/apk/device-2015-01-21-152934.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/apk/device-2015-01-21-152934.png
--------------------------------------------------------------------------------
/apk/device-2015-02-07-105356.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/apk/device-2015-02-07-105356.png
--------------------------------------------------------------------------------
/apk/device-2015-02-07-105501.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/apk/device-2015-02-07-105501.png
--------------------------------------------------------------------------------
/apk/device-2015-02-07-121646.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/apk/device-2015-02-07-121646.png
--------------------------------------------------------------------------------
/apk/last_number_redail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/apk/last_number_redail.png
--------------------------------------------------------------------------------
/gen/com/example/testkey/BuildConfig.java:
--------------------------------------------------------------------------------
1 | /** Automatically generated file. DO NOT MODIFY */
2 | package com.example.testkey;
3 |
4 | public final class BuildConfig {
5 | public final static boolean DEBUG = true;
6 | }
--------------------------------------------------------------------------------
/gen/com/example/testkey/R.java:
--------------------------------------------------------------------------------
1 | /* AUTO-GENERATED FILE. DO NOT MODIFY.
2 | *
3 | * This class was automatically generated by the
4 | * aapt tool from the resource data it found. It
5 | * should not be modified by hand.
6 | */
7 |
8 | package com.example.testkey;
9 |
10 | public final class R {
11 | public static final class attr {
12 | }
13 | public static final class dimen {
14 | /** Default screen margins, per the Android Design guidelines.
15 |
16 | Customize dimensions originally defined in res/values/dimens.xml (such as
17 | screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
18 |
19 | */
20 | public static final int activity_horizontal_margin=0x7f050000;
21 | public static final int activity_vertical_margin=0x7f050001;
22 | }
23 | public static final class drawable {
24 | public static final int ic_launcher=0x7f020000;
25 | }
26 | public static final class id {
27 | public static final int action_settings=0x7f090002;
28 | public static final int is_test_bt_checkbox=0x7f090000;
29 | public static final int textView=0x7f090001;
30 | }
31 | public static final class layout {
32 | public static final int activity_main=0x7f030000;
33 | }
34 | public static final class menu {
35 | public static final int main=0x7f080000;
36 | }
37 | public static final class raw {
38 | public static final int lapple=0x7f040000;
39 | public static final int silence10sec=0x7f040001;
40 | }
41 | public static final class string {
42 | public static final int action_settings=0x7f060001;
43 | public static final int app_name=0x7f060000;
44 | public static final int hello_world=0x7f060002;
45 | }
46 | public static final class style {
47 | /**
48 | Base application theme, dependent on API level. This theme is replaced
49 | by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
50 |
51 |
52 | Theme customizations available in newer API levels can go in
53 | res/values-vXX/styles.xml, while customizations related to
54 | backward-compatibility can go here.
55 |
56 |
57 | Base application theme for API 11+. This theme completely replaces
58 | AppBaseTheme from res/values/styles.xml on API 11+ devices.
59 |
60 | API 11 theme customizations can go here.
61 |
62 | Base application theme for API 14+. This theme completely replaces
63 | AppBaseTheme from BOTH res/values/styles.xml and
64 | res/values-v11/styles.xml on API 14+ devices.
65 |
66 | API 14 theme customizations can go here.
67 | */
68 | public static final int AppBaseTheme=0x7f070000;
69 | /** Application theme.
70 | All customizations that are NOT specific to a particular API-level can go here.
71 | */
72 | public static final int AppTheme=0x7f070001;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/ic_launcher-web.png
--------------------------------------------------------------------------------
/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-15
15 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
18 |
19 |
25 |
26 |
31 |
32 |
37 |
38 |
43 |
44 |
48 |
49 |
54 |
55 |
62 |
63 |
64 |
68 |
69 |
74 |
75 |
82 |
83 |
84 |
88 |
89 |
94 |
95 |
102 |
103 |
104 |
110 |
111 |
--------------------------------------------------------------------------------
/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/res/raw/lapple.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/res/raw/lapple.mp3
--------------------------------------------------------------------------------
/res/raw/silence10sec.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kangear/TestKey/1d03b397ff774fe5f223a5554c8f98c55c86a213/res/raw/silence10sec.mp3
--------------------------------------------------------------------------------
/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | TestKey
5 | Settings
6 | Hello world!
7 | 动态休眠设置休眠时间,根据蓝牙连接状态设置合适的休眠时间
8 | 使能动态休眠-单位(秒)
9 | 连接时:
10 | 断开时:
11 | 禁用时:
12 |
13 |
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/com/example/testkey/KeyService.java:
--------------------------------------------------------------------------------
1 | package com.example.testkey;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.bluetooth.BluetoothAdapter;
5 | import android.bluetooth.BluetoothProfile;
6 | import android.content.Context;
7 | import android.os.PowerManager;
8 | import android.provider.Settings;
9 | import android.util.Log;
10 | import android.view.KeyEvent;
11 | import android.widget.Toast;
12 |
13 | public class KeyService {
14 | private static final String LOG_TAG = "KeyService";
15 | private static int IS_NEED_REDIRECT = 0;
16 | private static final int BIT_BT_CONNECTED = (1 << 0);
17 | private static final int BIT_SCREEN_OFF = (1 << 1);
18 | private static final int NEED_REDIRECT = BIT_BT_CONNECTED | BIT_SCREEN_OFF;
19 | private final Context mContext;
20 |
21 | public KeyService(Context context) {
22 | this.mContext = context;
23 | }
24 |
25 | @SuppressLint("NewApi")
26 | public static boolean isNeedRedirect(Context context) {
27 | if(context == null) {
28 | return false;
29 | }
30 | IS_NEED_REDIRECT = 0;
31 | PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
32 | if(!powerManager.isScreenOn())
33 | IS_NEED_REDIRECT |= BIT_SCREEN_OFF;
34 | else
35 | IS_NEED_REDIRECT &= ~BIT_SCREEN_OFF;
36 |
37 | BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
38 | IS_NEED_REDIRECT |= parseBtState(mBluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET));
39 |
40 | Log.d(LOG_TAG, "IS_NEED_REDIRECT:" + IS_NEED_REDIRECT);
41 | return IS_NEED_REDIRECT == NEED_REDIRECT;
42 | }
43 |
44 | @SuppressLint("NewApi")
45 | public boolean isBtConect() {
46 | IS_NEED_REDIRECT = 0;
47 | BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
48 | IS_NEED_REDIRECT |= parseBtState(mBluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET));
49 |
50 | Log.d(LOG_TAG, "IS_NEED_REDIRECT:" + IS_NEED_REDIRECT);
51 | return (IS_NEED_REDIRECT & BIT_BT_CONNECTED) == BIT_BT_CONNECTED;
52 | }
53 |
54 | public static int parseBtState(int state) {
55 | Log.i(LOG_TAG, "state:" + state);
56 | int result = 0;
57 | switch(state) {
58 | case BluetoothAdapter.STATE_CONNECTED:
59 | Log.i(LOG_TAG, "STATE_CONNECTED");
60 | result |= BIT_BT_CONNECTED;
61 | break;
62 | case BluetoothAdapter.STATE_DISCONNECTING:
63 | case BluetoothAdapter.STATE_DISCONNECTED:
64 | Log.i(LOG_TAG, "STATE_DISCONNECTING");
65 | result &= ~BIT_BT_CONNECTED;
66 | break;
67 | }
68 | return result;
69 | }
70 |
71 | public static String parseKeyCode(int keyCode) {
72 | String ret = "";
73 | switch (keyCode) {
74 | case KeyEvent.KEYCODE_POWER:
75 | // 监控/拦截/屏蔽电源键 这里拦截不了
76 | ret = "get Key KEYCODE_POWER(KeyCode:" + keyCode + ")";
77 | break;
78 | case KeyEvent.KEYCODE_RIGHT_BRACKET:
79 | // 监控/拦截/屏蔽返回键
80 | ret = "get Key KEYCODE_RIGHT_BRACKET";
81 | break;
82 | case KeyEvent.KEYCODE_MENU:
83 | // 监控/拦截菜单键
84 | ret = "get Key KEYCODE_MENU";
85 | break;
86 | case KeyEvent.KEYCODE_HOME:
87 | // 由于Home键为系统键,此处不能捕获
88 | ret = "get Key KEYCODE_HOME";
89 | break;
90 | case KeyEvent.KEYCODE_DPAD_UP:
91 | // 监控/拦截/屏蔽上方向键
92 | ret = "get Key KEYCODE_DPAD_UP";
93 | break;
94 | case KeyEvent.KEYCODE_DPAD_LEFT:
95 | // 监控/拦截/屏蔽左方向键
96 | ret = "get Key KEYCODE_DPAD_LEFT";
97 | break;
98 | case KeyEvent.KEYCODE_DPAD_RIGHT:
99 | // 监控/拦截/屏蔽右方向键
100 | ret = "get Key KEYCODE_DPAD_RIGHT";
101 | break;
102 | case KeyEvent.KEYCODE_DPAD_DOWN:
103 | // 监控/拦截/屏蔽下方向键
104 | ret = "get Key KEYCODE_DPAD_DOWN";
105 | break;
106 | case KeyEvent.KEYCODE_DPAD_CENTER:
107 | // 监控/拦截/屏蔽中方向键
108 | ret = "get Key KEYCODE_DPAD_CENTER";
109 | break;
110 | case KeyEvent.FLAG_KEEP_TOUCH_MODE:
111 | // 监控/拦截/屏蔽长按
112 | ret = "get Key FLAG_KEEP_TOUCH_MODE";
113 | break;
114 | case KeyEvent.KEYCODE_VOLUME_DOWN:
115 | // 监控/拦截/屏蔽下方向键
116 | ret = "get Key KEYCODE_VOLUME_DOWN(KeyCode:" + keyCode + ")";
117 | break;
118 | case KeyEvent.KEYCODE_VOLUME_UP:
119 | // 监控/拦截/屏蔽中方向键
120 | ret = "get Key KEYCODE_VOLUME_UP(KeyCode:" + keyCode + ")";
121 | break;
122 | case 220:
123 | // case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
124 | // 监控/拦截/屏蔽亮度减键
125 | ret = "get Key KEYCODE_BRIGHTNESS_DOWN(KeyCode:" + keyCode + ")";
126 | break;
127 | case 221:
128 | // case KeyEvent.KEYCODE_BRIGHTNESS_UP:
129 | // 监控/拦截/屏蔽亮度加键
130 | ret = "get Key KEYCODE_BRIGHTNESS_UP(KeyCode:" + keyCode + ")";
131 | break;
132 | case KeyEvent.KEYCODE_MEDIA_PLAY:
133 | ret = "get Key KEYCODE_MEDIA_PLAY(KeyCode:" + keyCode + ")";
134 | break;
135 | case KeyEvent.KEYCODE_MEDIA_PAUSE:
136 | ret = "get Key KEYCODE_MEDIA_PAUSE(KeyCode:" + keyCode + ")";
137 | break;
138 | case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
139 | ret = "get Key KEYCODE_MEDIA_PREVIOUS(KeyCode:" + keyCode + ")";
140 | break;
141 | case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
142 | ret = "get Key KEYCODE_MEDIA_PLAY_PAUSE(KeyCode:" + keyCode + ")";
143 | break;
144 | case KeyEvent.KEYCODE_MEDIA_NEXT:
145 | ret = "get Key KEYCODE_MEDIA_NEXT(KeyCode:" + keyCode + ")";
146 | break;
147 | default:
148 | ret = "keyCode: "
149 | + keyCode
150 | + " (http://developer.android.com/reference/android/view/KeyEvent.html)";
151 | break;
152 | }
153 | return ret;
154 | }
155 |
156 | /**
157 | * 获得休眠时间 毫秒
158 | */
159 | public int getScreenOffTime() {
160 | int screenOffTime = 0;
161 | try {
162 | screenOffTime = Settings.System.getInt(mContext.getContentResolver(),
163 | Settings.System.SCREEN_OFF_TIMEOUT);
164 | } catch (Exception localException) {
165 |
166 | }
167 | return screenOffTime;
168 | }
169 |
170 | /**
171 | * 设置休眠时间 毫秒
172 | */
173 | public void setScreenOffTime(int paramInt) {
174 | if(mContext != null)
175 | Toast.makeText(mContext, "TestKey:将休眠时间设置为" + paramInt/1000 + "秒.", Toast.LENGTH_SHORT).show();
176 | try {
177 | Settings.System.putInt(mContext.getContentResolver(),
178 | Settings.System.SCREEN_OFF_TIMEOUT, paramInt);
179 | } catch (Exception localException) {
180 | localException.printStackTrace();
181 | }
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/src/com/example/testkey/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.testkey;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.FileOutputStream;
6 | import java.io.IOException;
7 |
8 | import android.annotation.SuppressLint;
9 | import android.app.Activity;
10 | import android.bluetooth.BluetoothAdapter;
11 | import android.content.BroadcastReceiver;
12 | import android.content.ComponentName;
13 | import android.content.Context;
14 | import android.content.Intent;
15 | import android.content.IntentFilter;
16 | import android.media.AudioManager;
17 | import android.os.Bundle;
18 | import android.util.Log;
19 | import android.view.KeyEvent;
20 | import android.view.View;
21 | import android.view.Window;
22 | import android.view.WindowManager;
23 | import android.widget.Button;
24 | import android.widget.CheckBox;
25 | import android.widget.CompoundButton;
26 | import android.widget.CompoundButton.OnCheckedChangeListener;
27 | import android.widget.EditText;
28 | import android.widget.TextView;
29 |
30 | @SuppressLint("InlinedApi")
31 | public class MainActivity extends Activity {
32 | private final static String LOG_TAG = "com.example.testkey";
33 | Context mContext;
34 | TextView mTextView;
35 | private CheckBox mCheckBox = null;
36 | public static boolean mIsEnableDSuspend = false;
37 | private final static int[] time = {10, 120, 125};
38 | private EditText connectTimeEditText;
39 | private EditText disconnectTimeEditText;
40 | private EditText disableTimeEditText;
41 | private String timeFile;
42 | private Button mButton;
43 |
44 | @Override
45 | protected void onCreate(Bundle savedInstanceState) {
46 | super.onCreate(savedInstanceState);
47 | setContentView(R.layout.activity_main);
48 | Log.d(LOG_TAG, "onCreate");
49 | mContext = this;
50 | displayMyself(mContext);
51 | mTextView = (TextView)findViewById(R.id.textView);
52 |
53 | IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
54 | filter.addAction(Intent.ACTION_SCREEN_ON);
55 | filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
56 | // Power
57 | registerReceiver(mBatInfoReceiver, filter);
58 | // Home
59 | final IntentFilter homeFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
60 | registerReceiver(homePressReceiver, homeFilter);
61 |
62 | connectTimeEditText = (EditText) this.findViewById(R.id.connected_time);
63 | disconnectTimeEditText = (EditText) this.findViewById(R.id.disconnected_time);
64 | disableTimeEditText = (EditText) this.findViewById(R.id.disable_time);
65 | mButton = (Button) this.findViewById(R.id.edit_button);
66 | mButton.setText("编辑");
67 |
68 | timeFile = "time.txt";
69 | printToast("开始测试按键!");
70 |
71 | mCheckBox = (CheckBox) this.findViewById(R.id.enable_dsuspend_checkbox);
72 | mCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
73 | @Override
74 | public void onCheckedChanged(CompoundButton buttonView,
75 | boolean isChecked) {
76 | mIsEnableDSuspend = isChecked;
77 | Intent intent = new Intent("android.intent.action.UPDATE_SUSPEND_TIME_BY_HAND");
78 | sendBroadcast(intent);
79 | }
80 | });
81 |
82 | // for service
83 | ((AudioManager)getSystemService(AUDIO_SERVICE)).registerMediaButtonEventReceiver(new ComponentName(
84 | this,
85 | MusicIntentReceiver.class));
86 |
87 | // check intent
88 | Intent intent = getIntent();
89 | if (intent != null) {
90 | String act = getIntent().getAction();
91 | if (act != null) {
92 | if (act.equals(Intent.ACTION_VOICE_COMMAND)) {
93 | // voice command
94 | Log.d(LOG_TAG, "VOICE_COMMAND");
95 | printToast("get Key VOICE_COMMAND");
96 | } else if (act.equals("android.intent.action.CALL_PRIVILEGED")
97 | || act.equals("android.intent.action.KANGEAR_LASTREDIAL_TO_VR")) {
98 | printToast("LAST_NUMBER_REDIAL(需要重定向:" + KeyService.isNeedRedirect(this) +")");
99 | if(KeyService.isNeedRedirect(this)) {
100 | startVoiceDial();
101 | displayMyself(mContext);
102 | finish();
103 | } else {
104 | printToast("DIAL_CUSTOM_NUMBER");
105 | dail(intent);
106 | displayMyself(mContext);
107 | finish();
108 | }
109 | } else {
110 | showMyself(mContext);
111 | }
112 | }
113 | }
114 |
115 | String content = getConfig(timeFile);
116 | if(content != null) {
117 | String ss[] = content.split(" ");
118 | if(ss != null && ss.length >= 3) {
119 | time[0] = Integer.valueOf(ss[0]);
120 | time[1] = Integer.valueOf(ss[1]);
121 | time[2] = Integer.valueOf(ss[2]);
122 | }
123 | }
124 | connectTimeEditText.setText(String.valueOf(time[0]));
125 | disconnectTimeEditText.setText(String.valueOf(time[1]));
126 | disableTimeEditText.setText(String.valueOf(time[2]));
127 | setEditTextEnable(false);
128 | }
129 |
130 | void updateConfig(String filename, String content) throws IOException {
131 | File file = new File(filename);
132 | file.delete();
133 | FileOutputStream outStream = openFileOutput(filename, Context.MODE_PRIVATE);
134 | Log.d("LOG_TAG", "write bytes:" + content.getBytes().length);
135 | outStream.write(content.getBytes());
136 | outStream.close();
137 | }
138 |
139 | String getConfig(String filename) {
140 | byte[] byteName = new byte[20];
141 | FileInputStream in;
142 | String ret = null;
143 | try {
144 | in = openFileInput(filename);
145 | int len = in.read(byteName);
146 | in.close();
147 | ret = new String(byteName, 0, len, "UTF-8");
148 | } catch (Exception e) {
149 | e.printStackTrace();
150 | }
151 | Log.d(LOG_TAG, "str:" + ret);
152 | return ret;
153 | }
154 |
155 | public static boolean isEnableDSuspend() {
156 | return mIsEnableDSuspend;
157 | }
158 |
159 | public static int[] getTime() {
160 | return time;
161 | }
162 |
163 | private void showMyself(Context context) {
164 | Window window=((Activity) context).getWindow();
165 | WindowManager.LayoutParams wl = window.getAttributes();
166 | wl.alpha=1.0f;
167 | window.setAttributes(wl);
168 | }
169 |
170 | private void displayMyself(Context context) {
171 | Window window=((Activity) context).getWindow();
172 | WindowManager.LayoutParams wl = window.getAttributes();
173 | wl.alpha=0.0f;
174 | window.setAttributes(wl);
175 | }
176 |
177 | private void startVoiceDial() {
178 | Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
179 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
180 | // Verify that the intent will resolve to an activity
181 | if (intent.resolveActivity(getPackageManager()) != null) {
182 | startActivity(intent);
183 | } else {
184 | Log.e(LOG_TAG, "没有发现语音拨号器!");
185 | }
186 | }
187 |
188 | private void dail(Intent intent) {
189 | Intent intent2 = new Intent(Intent.ACTION_CALL, intent.getData());
190 | // Verify that the intent will resolve to an activity
191 | if (intent2.resolveActivity(getPackageManager()) != null) {
192 | startActivity(intent2);
193 | } else {
194 | Log.e(LOG_TAG, "没有发现拨号器!");
195 | }
196 | }
197 |
198 | public void onClick(View v) {
199 | switch(v.getId()) {
200 | case R.id.edit_button:
201 | if(mButton.getText().toString().equals("编辑")) {
202 | mButton.setText("保存");
203 | setEditTextEnable(true);
204 | } else {
205 | mButton.setText("编辑");
206 | setEditTextEnable(false);
207 | try {
208 | time[0] = Integer.valueOf(connectTimeEditText.getText().toString());
209 | time[1] = Integer.valueOf(disconnectTimeEditText.getText().toString());
210 | time[2] = Integer.valueOf(disableTimeEditText.getText().toString());
211 | updateConfig(timeFile, time[0] + " "
212 | + time[1] + " " + time[2]);
213 | } catch (Exception e) {
214 | e.printStackTrace();
215 | }
216 | }
217 | }
218 | }
219 |
220 | void setEditTextEnable(boolean isEnable) {
221 | connectTimeEditText.setEnabled(isEnable);
222 | disconnectTimeEditText.setEnabled(isEnable);
223 | disableTimeEditText.setEnabled(isEnable);
224 | }
225 |
226 | @Override
227 | public void onDestroy() {
228 |
229 | // 解除注册 Power
230 | if (mBatInfoReceiver != null) {
231 | try {
232 | unregisterReceiver(mBatInfoReceiver);
233 | } catch (Exception e) {
234 | Log.e(LOG_TAG, "unregisterReceiver mBatInfoReceiver failure :"
235 | + e.getCause());
236 | }
237 | };
238 | // 解除注册 Home
239 | if (homePressReceiver != null) {
240 | try {
241 | unregisterReceiver(homePressReceiver);
242 | } catch (Exception e) {
243 | Log.e(LOG_TAG,"unregisterReceiver homePressReceiver failure :"
244 | + e.getCause());
245 | }
246 | };
247 |
248 | super.onDestroy();
249 | }
250 |
251 | @Override
252 | public boolean onKeyDown(int keyCode, KeyEvent event) {
253 | printToast(KeyService.parseKeyCode(keyCode));
254 | return true;
255 | //return super.onKeyDown(keyCode, event);
256 | }
257 |
258 | public void printToast(String str) {
259 | mTextView.setText(str);
260 | Log.i(LOG_TAG, str);
261 | }
262 |
263 | private final BroadcastReceiver homePressReceiver = new BroadcastReceiver() {
264 | final String SYSTEM_DIALOG_REASON_KEY = "reason";
265 | final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
266 |
267 | @Override
268 | public void onReceive(Context context, Intent intent) {
269 | String action = intent.getAction();
270 | if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
271 | String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
272 | if (reason != null
273 | && reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {
274 | // 自己随意控制程序,关闭...
275 | }
276 | }
277 | }
278 |
279 | };
280 | private final BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver() {
281 | @Override
282 | public void onReceive(final Context context, final Intent intent) {
283 |
284 | final String action = intent.getAction();
285 | if (Intent.ACTION_SCREEN_OFF.equals(action)) {
286 | printToast("get Key KEYCODE_POWER(KeyCode:26)-OFF");
287 | } else if(Intent.ACTION_SCREEN_ON.equals(action)){
288 | printToast("get Key KEYCODE_POWER(KeyCode:26)-NO");
289 | }
290 | }
291 | };
292 | }
293 |
--------------------------------------------------------------------------------
/src/com/example/testkey/MusicIntentReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.example.testkey;
18 |
19 | import android.annotation.SuppressLint;
20 | import android.bluetooth.BluetoothAdapter;
21 | import android.content.BroadcastReceiver;
22 | import android.content.Context;
23 | import android.content.Intent;
24 | import android.util.Log;
25 | import android.view.KeyEvent;
26 | import android.widget.Toast;
27 |
28 | /**
29 | * Receives broadcasted intents. In particular, we are interested in the
30 | * android.media.AUDIO_BECOMING_NOISY and android.intent.action.MEDIA_BUTTON
31 | * intents, which is broadcast, for example, when the user disconnects the
32 | * headphones. This class works because we are declaring it in a
33 | * <receiver> tag in AndroidManifest.xml.
34 | */
35 | @SuppressLint("InlinedApi")
36 | public class MusicIntentReceiver extends BroadcastReceiver {
37 | private static final String LOG_TAG = "MusicIntentReceiver";
38 | private Context mContext;
39 | private KeyService mKeyService;
40 |
41 | @Override
42 | public void onReceive(Context context, Intent intent) {
43 | mContext = context;
44 | mKeyService = new KeyService(mContext);
45 | if (intent.getAction().equals(
46 | android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
47 | Toast.makeText(context, "Headphones disconnected.",
48 | Toast.LENGTH_SHORT).show();
49 |
50 | // send an intent to our MusicService to telling it to pause the
51 | // audio
52 | // context.startService(new Intent(MusicService.ACTION_PAUSE));
53 |
54 | } else if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON)) {
55 | Log.i(LOG_TAG, "ACTION_MEDIA_BUTTON!");
56 | KeyEvent keyEvent = (KeyEvent) intent.getExtras().get(
57 | Intent.EXTRA_KEY_EVENT);
58 | if (keyEvent.getAction() != KeyEvent.ACTION_DOWN)
59 | return;
60 |
61 | switch (keyEvent.getKeyCode()) {
62 | case KeyEvent.KEYCODE_HEADSETHOOK:
63 | case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
64 | // context.startService(new
65 | // Intent(MusicService.ACTION_TOGGLE_PLAYBACK));
66 | break;
67 | case KeyEvent.KEYCODE_MEDIA_PLAY:
68 | // context.startService(new Intent(MusicService.ACTION_PLAY));
69 | break;
70 | case KeyEvent.KEYCODE_MEDIA_PAUSE:
71 | // context.startService(new Intent(MusicService.ACTION_PAUSE));
72 | break;
73 | case KeyEvent.KEYCODE_MEDIA_STOP:
74 | // context.startService(new Intent(MusicService.ACTION_STOP));
75 | break;
76 | case KeyEvent.KEYCODE_MEDIA_NEXT:
77 | // context.startService(new Intent(MusicService.ACTION_SKIP));
78 | break;
79 | case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
80 | // TODO: ensure that doing this in rapid succession actually
81 | // plays the
82 | // previous song
83 | // context.startService(new Intent(MusicService.ACTION_REWIND));
84 | break;
85 | }
86 | } else if (intent.getAction().equals(
87 | BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
88 | Log.i(LOG_TAG, "BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED");
89 |
90 | int state = intent.getIntExtra(
91 | BluetoothAdapter.EXTRA_CONNECTION_STATE, 0);
92 |
93 | if (state == BluetoothAdapter.STATE_CONNECTED
94 | || state == BluetoothAdapter.STATE_DISCONNECTED) {
95 | updateTime();
96 | }
97 | } else if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
98 | Log.i(LOG_TAG, "Intent.ACTION_BOOT_COMPLETED");
99 | updateTime();
100 | } else if (intent.getAction().equals("android.intent.action.UPDATE_SUSPEND_TIME_BY_HAND")) {
101 | Log.i(LOG_TAG, "Intent.UPDATE_SUSPEND_TIME_BY_HAND");
102 | updateTime();
103 | } else {
104 | Log.i(LOG_TAG, "other intent");
105 | }
106 | }
107 |
108 | void updateTime() {
109 | Log.i(LOG_TAG, "updateTime");
110 | if(MainActivity.isEnableDSuspend()) {
111 | if(mKeyService.isBtConect())
112 | mKeyService.setScreenOffTime(MainActivity.getTime()[0]*1000); // def secs
113 | else
114 | mKeyService.setScreenOffTime(MainActivity.getTime()[1]*1000); // def secs
115 | } else {
116 | mKeyService.setScreenOffTime(MainActivity.getTime()[2]*1000); // def secs
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------