├── LICENSE
├── README.md
├── okbluetooth
├── .gitignore
├── build.gradle
├── okbluetooth.iml
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── aidl
│ └── android
│ │ ├── bluetooth
│ │ ├── IBluetoothHeadset.aidl
│ │ ├── IBluetoothManager.aidl
│ │ ├── IBluetoothProfileServiceConnection.aidl
│ │ └── IBluetoothStateChangeCallback.aidl
│ │ ├── media
│ │ └── IAudioService.aidl
│ │ └── os
│ │ └── IPermissionController.aidl
│ ├── assets
│ └── test.mp3
│ ├── java
│ ├── android
│ │ ├── bluetooth
│ │ │ ├── BluetoothA2dp.java
│ │ │ ├── BluetoothHeadset.java
│ │ │ ├── BluetoothProfile.java
│ │ │ └── BluetoothUuid.java
│ │ ├── media
│ │ │ ├── AudioGain.java
│ │ │ ├── AudioGainConfig.java
│ │ │ ├── AudioHandle.java
│ │ │ ├── AudioPatch.java
│ │ │ ├── AudioPort.java
│ │ │ ├── AudioPortConfig.java
│ │ │ └── AudioSystem.java
│ │ └── os
│ │ │ ├── IServiceManager.java
│ │ │ ├── ServiceManager.java
│ │ │ └── SystemProperties.java
│ └── com
│ │ └── devyok
│ │ └── bluetooth
│ │ ├── AudioDevice.java
│ │ ├── AudioDeviceSelector.java
│ │ ├── AudioService.java
│ │ ├── Configuration.java
│ │ ├── ConnectionHelper.java
│ │ ├── OkBluetooth.java
│ │ ├── TelephonyService.java
│ │ ├── a2dp
│ │ ├── A2dpProfileService.java
│ │ └── BluetoothA2dpProfileService.java
│ │ ├── base
│ │ ├── BaseBluetoothStateChangedListener.java
│ │ ├── BluetoothAdapterService.java
│ │ ├── BluetoothAdapterStateListener.java
│ │ ├── BluetoothAndroidThread.java
│ │ ├── BluetoothException.java
│ │ ├── BluetoothProfileService.java
│ │ ├── BluetoothProfileServiceTemplate.java
│ │ ├── BluetoothRuntimeException.java
│ │ ├── BluetoothService.java
│ │ ├── BluetoothServiceLifecycle.java
│ │ ├── Executor.java
│ │ ├── StateInformation.java
│ │ └── TaskQueue.java
│ │ ├── connection
│ │ ├── AbstractBluetoothConnection.java
│ │ ├── BluetoothConnection.java
│ │ ├── BluetoothConnectionException.java
│ │ ├── BluetoothConnectionImpl.java
│ │ ├── BluetoothConnectionStateListener.java
│ │ ├── BluetoothConnectionTimeoutException.java
│ │ ├── BluetoothDeviceConnectionService.java
│ │ ├── Connection.java
│ │ ├── DefaultRetryPolicy.java
│ │ └── RetryPolicy.java
│ │ ├── debug
│ │ ├── DebugHelper.java
│ │ └── DebugUIConsoleActivity.java
│ │ ├── hfp
│ │ ├── BluetoothHeadsetProfileService.java
│ │ ├── HFPConnection.java
│ │ ├── HFPConnectionImpl.java
│ │ └── HeadsetProfileService.java
│ │ ├── message
│ │ ├── BluetoothMessage.java
│ │ ├── BluetoothMessageDispatcher.java
│ │ ├── BluetoothMessageHandler.java
│ │ └── BluetoothMessageReceiver.java
│ │ ├── sco
│ │ └── BluetoothSCOService.java
│ │ ├── spp
│ │ ├── AbstractSPPConnection.java
│ │ ├── DefaultSPPMessageParser.java
│ │ ├── SPPBluetoothMessageParser.java
│ │ ├── SPPConnectionInsecurePolicy.java
│ │ ├── SPPConnectionSecurePolicy.java
│ │ ├── SPPMessageParser.java
│ │ ├── SPPMessageReceiver.java
│ │ └── SppConnectionLoopChannelPolicy.java
│ │ └── utils
│ │ └── BluetoothUtils.java
│ └── res
│ ├── layout
│ ├── okbt_activity_debug_ui_console.xml
│ ├── okbt_audio_device_list.xml
│ └── okbt_audio_device_list_item.xml
│ └── values
│ ├── okbt_colors.xml
│ └── okbt_strings.xml
└── okbluetooth_demo
├── .gitignore
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── devyok
│ │ └── bluetooth
│ │ └── demo
│ │ ├── DemoApplication.java
│ │ ├── MainActivity.java
│ │ └── OkBluetoothAdapter.java
│ └── res
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── layout
│ └── activity_main.xml
│ └── values
│ ├── colors.xml
│ └── strings.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── test.jpg
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/devyok/ServiceManager/blob/master/LICENSE)
2 | [](https://jcenter.bintray.com/com/devyok/web/hybridmessenger-core/1.0.0/)
3 |
4 | # OkBluetooth
5 | Android蓝牙音频及消息通信框架
6 |
7 | ## 作用 ##
8 | - OkBluetooth主要帮助应用与蓝牙设备之间建立可靠的HFP或SPP连接,并同时建立稳定的SCO音频连接;
9 | - OkBluetooth会根据当前手机终端所连接的音频输出设备(蓝牙耳机/有线耳机/扬声器等)的状态来选择音频设备放音;
10 | - 可以使用OkBluetooth提供的接口,搭建自己的音频及消息的通信组件;
11 |
12 | ## 例子 ##
13 | - [OkBluetooth-Demo](https://github.com/devyok/OkBluetooth/tree/master/okbluetooth_demo)
14 |
15 | 在demo中参考OkBluetoothAdapter#onAppReady方法中是如何使用OkBluetooth接口的。
16 |
17 | - [查看所有蓝牙相关接口](https://github.com/devyok/OkBluetooth/blob/master/okbluetooth/src/main/java/com/devyok/bluetooth/OkBluetooth.java)
18 |
19 | ## License ##
20 | ServiceManager is released under the [Apache 2.0 license](https://github.com/devyok/OkBluetooth/blob/master/LICENSE).
21 |
22 | Copyright (C) 2018 DengWei.
--------------------------------------------------------------------------------
/okbluetooth/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/okbluetooth/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 |
6 |
7 |
8 | defaultConfig {
9 | minSdkVersion 19
10 | targetSdkVersion 26
11 | versionCode 10000
12 | versionName "1.0.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(dir: 'libs', include: ['*.jar'])
29 | }
30 |
--------------------------------------------------------------------------------
/okbluetooth/okbluetooth.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDebugSources
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
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 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/okbluetooth/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/aidl/android/bluetooth/IBluetoothHeadset.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008 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 android.bluetooth;
18 |
19 | import android.bluetooth.BluetoothDevice;
20 |
21 | /**
22 | * API for Bluetooth Headset service
23 | *
24 | * {@hide}
25 | */
26 | interface IBluetoothHeadset {
27 | // Public API
28 | boolean connect(in BluetoothDevice device);
29 | boolean disconnect(in BluetoothDevice device);
30 | List getConnectedDevices();
31 | List getDevicesMatchingConnectionStates(in int[] states);
32 | int getConnectionState(in BluetoothDevice device);
33 | boolean setPriority(in BluetoothDevice device, int priority);
34 | int getPriority(in BluetoothDevice device);
35 | boolean startVoiceRecognition(in BluetoothDevice device);
36 | boolean stopVoiceRecognition(in BluetoothDevice device);
37 | boolean isAudioConnected(in BluetoothDevice device);
38 | boolean sendVendorSpecificResultCode(in BluetoothDevice device,
39 | in String command,
40 | in String arg);
41 |
42 | // APIs that can be made public in future
43 | int getBatteryUsageHint(in BluetoothDevice device);
44 |
45 | // Internal functions, not be made public
46 | boolean acceptIncomingConnect(in BluetoothDevice device);
47 | boolean rejectIncomingConnect(in BluetoothDevice device);
48 | int getAudioState(in BluetoothDevice device);
49 |
50 | boolean isAudioOn();
51 | boolean connectAudio();
52 | boolean disconnectAudio();
53 | boolean startScoUsingVirtualVoiceCall(in BluetoothDevice device);
54 | boolean stopScoUsingVirtualVoiceCall(in BluetoothDevice device);
55 | void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type);
56 | void clccResponse(int index, int direction, int status, int mode, boolean mpty,
57 | String number, int type);
58 | boolean enableWBS();
59 | boolean disableWBS();
60 | }
61 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/aidl/android/bluetooth/IBluetoothManager.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 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 android.bluetooth;
18 |
19 | import android.bluetooth.IBluetoothProfileServiceConnection;
20 | import android.bluetooth.IBluetoothStateChangeCallback;
21 |
22 | /**
23 | * System private API for talking with the Bluetooth service.
24 | *
25 | * {@hide}
26 | */
27 | interface IBluetoothManager
28 | {
29 | void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
30 | void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
31 | boolean isEnabled();
32 | boolean enable();
33 | boolean enableNoAutoConnect();
34 | boolean disable(boolean persist);
35 |
36 | boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
37 | void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
38 |
39 | String getAddress();
40 | String getName();
41 |
42 | boolean isBleScanAlwaysAvailable();
43 | int updateBleAppCount(IBinder b, boolean enable);
44 | boolean isBleAppPresent();
45 | }
46 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/aidl/android/bluetooth/IBluetoothProfileServiceConnection.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 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 android.bluetooth;
18 |
19 | import android.content.ComponentName;
20 | import android.os.IBinder;
21 |
22 | /**
23 | * Callback for bluetooth profile connections.
24 | *
25 | * {@hide}
26 | */
27 | interface IBluetoothProfileServiceConnection {
28 | void onServiceConnected(in ComponentName comp, in IBinder service);
29 | void onServiceDisconnected(in ComponentName comp);
30 | }
31 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/aidl/android/bluetooth/IBluetoothStateChangeCallback.aidl:
--------------------------------------------------------------------------------
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 android.bluetooth;
18 |
19 | /**
20 | * System private API for Bluetooth state change callback.
21 | *
22 | * {@hide}
23 | */
24 | interface IBluetoothStateChangeCallback
25 | {
26 | void onBluetoothStateChange(boolean on);
27 | }
28 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/aidl/android/media/IAudioService.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 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 android.media;
18 |
19 |
20 | /**
21 | * {@hide}
22 | */
23 | interface IAudioService {
24 |
25 | void setBluetoothA2dpOn(boolean on);
26 |
27 | boolean isBluetoothA2dpOn();
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/aidl/android/os/IPermissionController.aidl:
--------------------------------------------------------------------------------
1 | /* //device/java/android/android/os/IPowerManager.aidl
2 | **
3 | ** Copyright 2007, The Android Open Source Project
4 | **
5 | ** Licensed under the Apache License, Version 2.0 (the "License");
6 | ** you may not use this file except in compliance with the License.
7 | ** You may obtain a copy of the License at
8 | **
9 | ** http://www.apache.org/licenses/LICENSE-2.0
10 | **
11 | ** Unless required by applicable law or agreed to in writing, software
12 | ** distributed under the License is distributed on an "AS IS" BASIS,
13 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | ** See the License for the specific language governing permissions and
15 | ** limitations under the License.
16 | */
17 |
18 | package android.os;
19 |
20 | /** @hide */
21 | interface IPermissionController {
22 | boolean checkPermission(String permission, int pid, int uid);
23 | String[] getPackagesForUid(int uid);
24 | boolean isRuntimePermission(String permission);
25 | }
26 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/assets/test.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devyok/OkBluetooth/49be79259c5e935f9eb8ad1f47f1c5dc6ba0a74d/okbluetooth/src/main/assets/test.mp3
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/android/bluetooth/BluetoothProfile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2010-2014 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 |
18 | package android.bluetooth;
19 |
20 | import java.util.List;
21 |
22 | /**
23 | * Public APIs for the Bluetooth Profiles.
24 | *
25 | *
Clients should call {@link BluetoothAdapter#getProfileProxy},
26 | * to get the Profile Proxy. Each public profile implements this
27 | * interface.
28 | */
29 | public interface BluetoothProfile {
30 |
31 | /**
32 | * Extra for the connection state intents of the individual profiles.
33 | *
34 | * This extra represents the current connection state of the profile of the
35 | * Bluetooth device.
36 | */
37 | public static final String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
38 |
39 | /**
40 | * Extra for the connection state intents of the individual profiles.
41 | *
42 | * This extra represents the previous connection state of the profile of the
43 | * Bluetooth device.
44 | */
45 | public static final String EXTRA_PREVIOUS_STATE =
46 | "android.bluetooth.profile.extra.PREVIOUS_STATE";
47 |
48 | /** The profile is in disconnected state */
49 | public static final int STATE_DISCONNECTED = 0;
50 | /** The profile is in connecting state */
51 | public static final int STATE_CONNECTING = 1;
52 | /** The profile is in connected state */
53 | public static final int STATE_CONNECTED = 2;
54 | /** The profile is in disconnecting state */
55 | public static final int STATE_DISCONNECTING = 3;
56 |
57 | /**
58 | * Headset and Handsfree profile
59 | */
60 | public static final int HEADSET = 1;
61 |
62 | /**
63 | * A2DP profile.
64 | */
65 | public static final int A2DP = 2;
66 |
67 | /**
68 | * Health Profile
69 | */
70 | public static final int HEALTH = 3;
71 |
72 | /**
73 | * Input Device Profile
74 | * @hide
75 | */
76 | public static final int INPUT_DEVICE = 4;
77 |
78 | /**
79 | * PAN Profile
80 | * @hide
81 | */
82 | public static final int PAN = 5;
83 |
84 | /**
85 | * PBAP
86 | * @hide
87 | */
88 | public static final int PBAP = 6;
89 |
90 | /**
91 | * GATT
92 | */
93 | static public final int GATT = 7;
94 |
95 | /**
96 | * GATT_SERVER
97 | */
98 | static public final int GATT_SERVER = 8;
99 |
100 | /**
101 | * MAP Profile
102 | * @hide
103 | */
104 | public static final int MAP = 9;
105 |
106 | /*
107 | * SAP Profile
108 | * @hide
109 | */
110 | public static final int SAP = 10;
111 |
112 | /**
113 | * A2DP Sink Profile
114 | * @hide
115 | */
116 | public static final int A2DP_SINK = 11;
117 |
118 | /**
119 | * AVRCP Controller Profile
120 | * @hide
121 | */
122 | public static final int AVRCP_CONTROLLER = 12;
123 |
124 | /**
125 | * Headset Client - HFP HF Role
126 | * @hide
127 | */
128 | public static final int HEADSET_CLIENT = 16;
129 |
130 | /**
131 | * Default priority for devices that we try to auto-connect to and
132 | * and allow incoming connections for the profile
133 | * @hide
134 | **/
135 | public static final int PRIORITY_AUTO_CONNECT = 1000;
136 |
137 | /**
138 | * Default priority for devices that allow incoming
139 | * and outgoing connections for the profile
140 | * @hide
141 | **/
142 | public static final int PRIORITY_ON = 100;
143 |
144 | /**
145 | * Default priority for devices that does not allow incoming
146 | * connections and outgoing connections for the profile.
147 | * @hide
148 | **/
149 | public static final int PRIORITY_OFF = 0;
150 |
151 | /**
152 | * Default priority when not set or when the device is unpaired
153 | * @hide
154 | * */
155 | public static final int PRIORITY_UNDEFINED = -1;
156 |
157 | /**
158 | * Get connected devices for this specific profile.
159 | *
160 | *
Return the set of devices which are in state {@link #STATE_CONNECTED}
161 | *
162 | *
Requires {@link android.Manifest.permission#BLUETOOTH} permission.
163 | *
164 | * @return List of devices. The list will be empty on error.
165 | */
166 | public List getConnectedDevices();
167 |
168 | /**
169 | * Get a list of devices that match any of the given connection
170 | * states.
171 | *
172 | *
If none of the devices match any of the given states,
173 | * an empty list will be returned.
174 | *
175 | *
Requires {@link android.Manifest.permission#BLUETOOTH} permission.
176 | *
177 | * @param states Array of states. States can be one of
178 | * {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
179 | * {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
180 | * @return List of devices. The list will be empty on error.
181 | */
182 | public List getDevicesMatchingConnectionStates(int[] states);
183 |
184 | /**
185 | * Get the current connection state of the profile
186 | *
187 | *
Requires {@link android.Manifest.permission#BLUETOOTH} permission.
188 | *
189 | * @param device Remote bluetooth device.
190 | * @return State of the profile connection. One of
191 | * {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
192 | * {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
193 | */
194 | public int getConnectionState(BluetoothDevice device);
195 |
196 | /**
197 | * An interface for notifying BluetoothProfile IPC clients when they have
198 | * been connected or disconnected to the service.
199 | */
200 | public interface ServiceListener {
201 | /**
202 | * Called to notify the client when the proxy object has been
203 | * connected to the service.
204 | * @param profile - One of {@link #HEALTH}, {@link #HEADSET} or
205 | * {@link #A2DP}
206 | * @param proxy - One of {@link BluetoothHealth}, {@link BluetoothHeadset} or
207 | * {@link BluetoothA2dp}
208 | */
209 | public void onServiceConnected(int profile, BluetoothProfile proxy);
210 |
211 | /**
212 | * Called to notify the client that this proxy object has been
213 | * disconnected from the service.
214 | * @param profile - One of {@link #HEALTH}, {@link #HEADSET} or
215 | * {@link #A2DP}
216 | */
217 | public void onServiceDisconnected(int profile);
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/android/media/AudioGain.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 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 android.media;
18 |
19 | /**
20 | * The AudioGain describes a gain controller. Gain controllers are exposed by
21 | * audio ports when the gain is configurable at this port's input or output.
22 | * Gain values are expressed in millibels.
23 | * A gain controller has the following attributes:
24 | * - mode: defines modes of operation or features
25 | * MODE_JOINT: all channel gains are controlled simultaneously
26 | * MODE_CHANNELS: each channel gain is controlled individually
27 | * MODE_RAMP: ramps can be applied when gain changes
28 | * - channel mask: indicates for which channels the gain can be controlled
29 | * - min value: minimum gain value in millibel
30 | * - max value: maximum gain value in millibel
31 | * - default value: gain value after reset in millibel
32 | * - step value: granularity of gain control in millibel
33 | * - min ramp duration: minimum ramp duration in milliseconds
34 | * - max ramp duration: maximum ramp duration in milliseconds
35 | *
36 | * This object is always created by the framework and read only by applications.
37 | * Applications get a list of AudioGainDescriptors from AudioPortDescriptor.gains() and can build a
38 | * valid gain configuration from AudioGain.buildConfig()
39 | * @hide
40 | */
41 | public class AudioGain {
42 |
43 | /**
44 | * Bit of AudioGain.mode() field indicating that
45 | * all channel gains are controlled simultaneously
46 | */
47 | public static final int MODE_JOINT = 1;
48 | /**
49 | * Bit of AudioGain.mode() field indicating that
50 | * each channel gain is controlled individually
51 | */
52 | public static final int MODE_CHANNELS = 2;
53 | /**
54 | * Bit of AudioGain.mode() field indicating that
55 | * ramps can be applied when gain changes. The type of ramp (linear, log etc...) is
56 | * implementation specific.
57 | */
58 | public static final int MODE_RAMP = 4;
59 |
60 | private final int mIndex;
61 | private final int mMode;
62 | private final int mChannelMask;
63 | private final int mMinValue;
64 | private final int mMaxValue;
65 | private final int mDefaultValue;
66 | private final int mStepValue;
67 | private final int mRampDurationMinMs;
68 | private final int mRampDurationMaxMs;
69 |
70 | // The channel mask passed to the constructor is as specified in AudioFormat
71 | // (e.g. AudioFormat.CHANNEL_OUT_STEREO)
72 | AudioGain(int index, int mode, int channelMask,
73 | int minValue, int maxValue, int defaultValue, int stepValue,
74 | int rampDurationMinMs, int rampDurationMaxMs) {
75 | mIndex = index;
76 | mMode = mode;
77 | mChannelMask = channelMask;
78 | mMinValue = minValue;
79 | mMaxValue = maxValue;
80 | mDefaultValue = defaultValue;
81 | mStepValue = stepValue;
82 | mRampDurationMinMs = rampDurationMinMs;
83 | mRampDurationMaxMs = rampDurationMaxMs;
84 | }
85 |
86 | /**
87 | * Bit field indicating supported modes of operation
88 | */
89 | public int mode() {
90 | return mMode;
91 | }
92 |
93 | /**
94 | * Indicates for which channels the gain can be controlled
95 | * (e.g. AudioFormat.CHANNEL_OUT_STEREO)
96 | */
97 | public int channelMask() {
98 | return mChannelMask;
99 | }
100 |
101 | /**
102 | * Minimum gain value in millibel
103 | */
104 | public int minValue() {
105 | return mMinValue;
106 | }
107 |
108 | /**
109 | * Maximum gain value in millibel
110 | */
111 | public int maxValue() {
112 | return mMaxValue;
113 | }
114 |
115 | /**
116 | * Default gain value in millibel
117 | */
118 | public int defaultValue() {
119 | return mDefaultValue;
120 | }
121 |
122 | /**
123 | * Granularity of gain control in millibel
124 | */
125 | public int stepValue() {
126 | return mStepValue;
127 | }
128 |
129 | /**
130 | * Minimum ramp duration in milliseconds
131 | * 0 if MODE_RAMP not set
132 | */
133 | public int rampDurationMinMs() {
134 | return mRampDurationMinMs;
135 | }
136 |
137 | /**
138 | * Maximum ramp duration in milliseconds
139 | * 0 if MODE_RAMP not set
140 | */
141 | public int rampDurationMaxMs() {
142 | return mRampDurationMaxMs;
143 | }
144 |
145 | /**
146 | * Build a valid gain configuration for this gain controller for use by
147 | * AudioPortDescriptor.setGain()
148 | * @param mode: desired mode of operation
149 | * @param channelMask: channels of which the gain should be modified.
150 | * @param values: gain values for each channels.
151 | * @param rampDurationMs: ramp duration if mode MODE_RAMP is set.
152 | * ignored if MODE_JOINT.
153 | */
154 | public AudioGainConfig buildConfig(int mode, int channelMask,
155 | int[] values, int rampDurationMs) {
156 | //TODO: check params here
157 | return new AudioGainConfig(mIndex, this, mode, channelMask, values, rampDurationMs);
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/android/media/AudioGainConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 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 android.media;
18 |
19 | /**
20 | * The AudioGainConfig is used by APIs setting or getting values on a given gain
21 | * controller. It contains a valid configuration (value, channels...) for a gain controller
22 | * exposed by an audio port.
23 | * @see AudioGain
24 | * @see AudioPort
25 | * @hide
26 | */
27 | public class AudioGainConfig {
28 | AudioGain mGain;
29 | private final int mIndex;
30 | private final int mMode;
31 | private final int mChannelMask;
32 | private final int mValues[];
33 | private final int mRampDurationMs;
34 |
35 | AudioGainConfig(int index, AudioGain gain, int mode, int channelMask,
36 | int[] values, int rampDurationMs) {
37 | mIndex = index;
38 | mGain = gain;
39 | mMode = mode;
40 | mChannelMask = channelMask;
41 | mValues = values;
42 | mRampDurationMs = rampDurationMs;
43 | }
44 |
45 | /**
46 | * get the index of the parent gain.
47 | * frameworks use only.
48 | */
49 | int index() {
50 | return mIndex;
51 | }
52 |
53 | /**
54 | * Bit field indicating requested modes of operation. See {@link AudioGain#MODE_JOINT},
55 | * {@link AudioGain#MODE_CHANNELS}, {@link AudioGain#MODE_RAMP}
56 | */
57 | public int mode() {
58 | return mMode;
59 | }
60 |
61 | /**
62 | * Indicates for which channels the gain is set.
63 | * See {@link AudioFormat#CHANNEL_OUT_STEREO}, {@link AudioFormat#CHANNEL_OUT_MONO} ...
64 | */
65 | public int channelMask() {
66 | return mChannelMask;
67 | }
68 |
69 | /**
70 | * Gain values for each channel in the order of bits set in
71 | * channelMask() from LSB to MSB
72 | */
73 | public int[] values() {
74 | return mValues;
75 | }
76 |
77 | /**
78 | * Ramp duration in milliseconds. N/A if mode() does not
79 | * specify MODE_RAMP.
80 | */
81 | public int rampDurationMs() {
82 | return mRampDurationMs;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/android/media/AudioHandle.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 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 android.media;
18 |
19 | /**
20 | * The AudioHandle is used by the audio framework implementation to
21 | * uniquely identify a particular component of the routing topology
22 | * (AudioPort or AudioPatch)
23 | * It is not visible or used at the API.
24 | */
25 | class AudioHandle {
26 | private final int mId;
27 |
28 | AudioHandle(int id) {
29 | mId = id;
30 | }
31 |
32 | int id() {
33 | return mId;
34 | }
35 |
36 | @Override
37 | public boolean equals(Object o) {
38 | if (o == null || !(o instanceof AudioHandle)) {
39 | return false;
40 | }
41 | AudioHandle ah = (AudioHandle)o;
42 | return mId == ah.id();
43 | }
44 |
45 | @Override
46 | public int hashCode() {
47 | return mId;
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | return Integer.toString(mId);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/android/media/AudioPatch.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 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 android.media;
18 |
19 |
20 | /**
21 | * An AudioPatch describes a connection between audio sources and audio sinks.
22 | * An audio source can be an output mix (playback AudioBus) or an input device (microphone).
23 | * An audio sink can be an output device (speaker) or an input mix (capture AudioBus).
24 | * An AudioPatch is created by AudioManager.createAudioPatch() and released by
25 | * AudioManager.releaseAudioPatch()
26 | * It contains the list of source and sink AudioPortConfig showing audio port configurations
27 | * being connected.
28 | * @hide
29 | */
30 | public class AudioPatch {
31 |
32 | private final AudioHandle mHandle;
33 | private final AudioPortConfig[] mSources;
34 | private final AudioPortConfig[] mSinks;
35 |
36 | AudioPatch(AudioHandle patchHandle, AudioPortConfig[] sources, AudioPortConfig[] sinks) {
37 | mHandle = patchHandle;
38 | mSources = sources;
39 | mSinks = sinks;
40 | }
41 |
42 | /**
43 | * Retrieve the list of sources of this audio patch.
44 | */
45 | public AudioPortConfig[] sources() {
46 | return mSources;
47 | }
48 |
49 | /**
50 | * Retreive the list of sinks of this audio patch.
51 | */
52 | public AudioPortConfig[] sinks() {
53 | return mSinks;
54 | }
55 |
56 | @Override
57 | public String toString() {
58 | StringBuilder s = new StringBuilder();
59 | s.append("mHandle: ");
60 | s.append(mHandle.toString());
61 |
62 | s.append(" mSources: {");
63 | for (AudioPortConfig source : mSources) {
64 | s.append(source.toString());
65 | s.append(", ");
66 | }
67 | s.append("} mSinks: {");
68 | for (AudioPortConfig sink : mSinks) {
69 | s.append(sink.toString());
70 | s.append(", ");
71 | }
72 | s.append("}");
73 |
74 | return s.toString();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/android/media/AudioPort.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 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 android.media;
18 |
19 | /**
20 | * An audio port is a node of the audio framework or hardware that can be connected to or
21 | * disconnect from another audio node to create a specific audio routing configuration.
22 | * Examples of audio ports are an output device (speaker) or an output mix (see AudioMixPort).
23 | * All attributes that are relevant for applications to make routing selection are decribed
24 | * in an AudioPort, in particular:
25 | * - possible channel mask configurations.
26 | * - audio format (PCM 16bit, PCM 24bit...)
27 | * - gain: a port can be associated with one or more gain controllers (see AudioGain).
28 | *
29 | * This object is always created by the framework and read only by applications.
30 | * A list of all audio port descriptors currently available for applications to control
31 | * is obtained by AudioManager.listAudioPorts().
32 | * An application can obtain an AudioPortConfig for a valid configuration of this port
33 | * by calling AudioPort.buildConfig() and use this configuration
34 | * to create a connection between audio sinks and sources with AudioManager.connectAudioPatch()
35 | *
36 | * @hide
37 | */
38 | public class AudioPort {
39 | private static final String TAG = "AudioPort";
40 |
41 | /**
42 | * For use by the audio framework.
43 | */
44 | public static final int ROLE_NONE = 0;
45 | /**
46 | * The audio port is a source (produces audio)
47 | */
48 | public static final int ROLE_SOURCE = 1;
49 | /**
50 | * The audio port is a sink (consumes audio)
51 | */
52 | public static final int ROLE_SINK = 2;
53 |
54 | /**
55 | * audio port type for use by audio framework implementation
56 | */
57 | public static final int TYPE_NONE = 0;
58 | /**
59 | */
60 | public static final int TYPE_DEVICE = 1;
61 | /**
62 | */
63 | public static final int TYPE_SUBMIX = 2;
64 | /**
65 | */
66 | public static final int TYPE_SESSION = 3;
67 |
68 |
69 | AudioHandle mHandle;
70 | protected final int mRole;
71 | private final String mName;
72 | private final int[] mSamplingRates;
73 | private final int[] mChannelMasks;
74 | private final int[] mChannelIndexMasks;
75 | private final int[] mFormats;
76 | private final AudioGain[] mGains;
77 | private AudioPortConfig mActiveConfig;
78 |
79 | AudioPort(AudioHandle handle, int role, String name,
80 | int[] samplingRates, int[] channelMasks, int[] channelIndexMasks,
81 | int[] formats, AudioGain[] gains) {
82 |
83 | mHandle = handle;
84 | mRole = role;
85 | mName = name;
86 | mSamplingRates = samplingRates;
87 | mChannelMasks = channelMasks;
88 | mChannelIndexMasks = channelIndexMasks;
89 | mFormats = formats;
90 | mGains = gains;
91 | }
92 |
93 | AudioHandle handle() {
94 | return mHandle;
95 | }
96 |
97 | /**
98 | * Get the system unique device ID.
99 | */
100 | public int id() {
101 | return mHandle.id();
102 | }
103 |
104 |
105 | /**
106 | * Get the audio port role
107 | */
108 | public int role() {
109 | return mRole;
110 | }
111 |
112 | /**
113 | * Get the human-readable name of this port. Perhaps an internal
114 | * designation or an physical device.
115 | */
116 | public String name() {
117 | return mName;
118 | }
119 |
120 | /**
121 | * Get the list of supported sampling rates
122 | * Empty array if sampling rate is not relevant for this audio port
123 | */
124 | public int[] samplingRates() {
125 | return mSamplingRates;
126 | }
127 |
128 | /**
129 | * Get the list of supported channel mask configurations
130 | * (e.g AudioFormat.CHANNEL_OUT_STEREO)
131 | * Empty array if channel mask is not relevant for this audio port
132 | */
133 | public int[] channelMasks() {
134 | return mChannelMasks;
135 | }
136 |
137 | /**
138 | * Get the list of supported channel index mask configurations
139 | * (e.g 0x0003 means 2 channel, 0x000F means 4 channel....)
140 | * Empty array if channel index mask is not relevant for this audio port
141 | */
142 | public int[] channelIndexMasks() {
143 | return mChannelIndexMasks;
144 | }
145 |
146 | /**
147 | * Get the list of supported audio format configurations
148 | * (e.g AudioFormat.ENCODING_PCM_16BIT)
149 | * Empty array if format is not relevant for this audio port
150 | */
151 | public int[] formats() {
152 | return mFormats;
153 | }
154 |
155 | /**
156 | * Get the list of gain descriptors
157 | * Empty array if this port does not have gain control
158 | */
159 | public AudioGain[] gains() {
160 | return mGains;
161 | }
162 |
163 | /**
164 | * Get the gain descriptor at a given index
165 | */
166 | AudioGain gain(int index) {
167 | if (index < 0 || index >= mGains.length) {
168 | return null;
169 | }
170 | return mGains[index];
171 | }
172 |
173 | /**
174 | * Build a specific configuration of this audio port for use by methods
175 | * like AudioManager.connectAudioPatch().
176 | * @param channelMask The desired channel mask. AudioFormat.CHANNEL_OUT_DEFAULT if no change
177 | * from active configuration requested.
178 | * @param format The desired audio format. AudioFormat.ENCODING_DEFAULT if no change
179 | * from active configuration requested.
180 | * @param gain The desired gain. null if no gain changed requested.
181 | */
182 | public AudioPortConfig buildConfig(int samplingRate, int channelMask, int format,
183 | AudioGainConfig gain) {
184 | return new AudioPortConfig(this, samplingRate, channelMask, format, gain);
185 | }
186 |
187 | /**
188 | * Get currently active configuration of this audio port.
189 | */
190 | public AudioPortConfig activeConfig() {
191 | return mActiveConfig;
192 | }
193 |
194 | @Override
195 | public boolean equals(Object o) {
196 | if (o == null || !(o instanceof AudioPort)) {
197 | return false;
198 | }
199 | AudioPort ap = (AudioPort)o;
200 | return mHandle.equals(ap.handle());
201 | }
202 |
203 | @Override
204 | public int hashCode() {
205 | return mHandle.hashCode();
206 | }
207 |
208 | @Override
209 | public String toString() {
210 | String role = Integer.toString(mRole);
211 | switch (mRole) {
212 | case ROLE_NONE:
213 | role = "NONE";
214 | break;
215 | case ROLE_SOURCE:
216 | role = "SOURCE";
217 | break;
218 | case ROLE_SINK:
219 | role = "SINK";
220 | break;
221 | }
222 | return "{mHandle: " + mHandle
223 | + ", mRole: " + role
224 | + "}";
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/android/media/AudioPortConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 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 android.media;
18 |
19 | /**
20 | * An AudioPortConfig contains a possible configuration of an audio port chosen
21 | * among all possible attributes described by an AudioPort.
22 | * An AudioPortConfig is created by AudioPort.buildConfiguration().
23 | * AudioPorts are used to specify the sources and sinks of a patch created
24 | * with AudioManager.connectAudioPatch().
25 | * Several specialized versions of AudioPortConfig exist to handle different categories of
26 | * audio ports and their specific attributes:
27 | * - AudioDevicePortConfig for input (e.g micropohone) and output devices (e.g speaker)
28 | * - AudioMixPortConfig for input or output streams of the audio framework.
29 | * @hide
30 | */
31 |
32 | public class AudioPortConfig {
33 | final AudioPort mPort;
34 | private final int mSamplingRate;
35 | private final int mChannelMask;
36 | private final int mFormat;
37 | private final AudioGainConfig mGain;
38 |
39 | // mConfigMask indicates which fields in this configuration should be
40 | // taken into account. Used with AudioSystem.setAudioPortConfig()
41 | // framework use only.
42 | static final int SAMPLE_RATE = 0x1;
43 | static final int CHANNEL_MASK = 0x2;
44 | static final int FORMAT = 0x4;
45 | static final int GAIN = 0x8;
46 | int mConfigMask;
47 |
48 | AudioPortConfig(AudioPort port, int samplingRate, int channelMask, int format,
49 | AudioGainConfig gain) {
50 | mPort = port;
51 | mSamplingRate = samplingRate;
52 | mChannelMask = channelMask;
53 | mFormat = format;
54 | mGain = gain;
55 | mConfigMask = 0;
56 | }
57 |
58 | /**
59 | * Returns the audio port this AudioPortConfig is issued from.
60 | */
61 | public AudioPort port() {
62 | return mPort;
63 | }
64 |
65 | /**
66 | * Sampling rate configured for this AudioPortConfig.
67 | */
68 | public int samplingRate() {
69 | return mSamplingRate;
70 | }
71 |
72 | /**
73 | * Channel mask configuration (e.g AudioFormat.CHANNEL_CONFIGURATION_STEREO).
74 | */
75 | public int channelMask() {
76 | return mChannelMask;
77 | }
78 |
79 | /**
80 | * Audio format configuration (e.g AudioFormat.ENCODING_PCM_16BIT).
81 | */
82 | public int format() {
83 | return mFormat;
84 | }
85 |
86 | /**
87 | * The gain configuration if this port supports gain control, null otherwise
88 | * @see AudioGainConfig.
89 | */
90 | public AudioGainConfig gain() {
91 | return mGain;
92 | }
93 |
94 | @Override
95 | public String toString() {
96 | return "{mPort:" + mPort
97 | + ", mSamplingRate:" + mSamplingRate
98 | + ", mChannelMask: " + mChannelMask
99 | + ", mFormat:" + mFormat
100 | + ", mGain:" + mGain
101 | + "}";
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/android/os/IServiceManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2006 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 android.os;
18 |
19 | /**
20 | * Basic interface for finding and publishing system services.
21 | *
22 | * An implementation of this interface is usually published as the
23 | * global context object, which can be retrieved via
24 | * BinderNative.getContextObject(). An easy way to retrieve this
25 | * is with the static method BnServiceManager.getDefault().
26 | *
27 | * @hide
28 | */
29 | public interface IServiceManager extends IInterface
30 | {
31 | /**
32 | * Retrieve an existing service called @a name from the
33 | * service manager. Blocks for a few seconds waiting for it to be
34 | * published if it does not already exist.
35 | */
36 | public IBinder getService(String name) throws RemoteException;
37 |
38 | /**
39 | * Retrieve an existing service called @a name from the
40 | * service manager. Non-blocking.
41 | */
42 | public IBinder checkService(String name) throws RemoteException;
43 |
44 | /**
45 | * Place a new @a service called @a name into the service
46 | * manager.
47 | */
48 | public void addService(String name, IBinder service, boolean allowIsolated)
49 | throws RemoteException;
50 |
51 | /**
52 | * Return a list of all currently running services.
53 | */
54 | public String[] listServices() throws RemoteException;
55 |
56 | /**
57 | * Assign a permission controller to the service manager. After set, this
58 | * interface is checked before any services are added.
59 | */
60 | public void setPermissionController(IPermissionController controller)
61 | throws RemoteException;
62 |
63 | static final String descriptor = "android.os.IServiceManager";
64 |
65 | int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
66 | int CHECK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
67 | int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
68 | int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
69 | int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
70 | int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5;
71 | }
72 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/android/os/ServiceManager.java:
--------------------------------------------------------------------------------
1 | package android.os;
2 | /*
3 | * Copyright (C) 2007 The Android Open Source Project
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 |
19 |
20 |
21 | import java.util.HashMap;
22 | import java.util.Map;
23 |
24 | /** @hide */
25 | public final class ServiceManager {
26 | private static final String TAG = "ServiceManager";
27 |
28 | private static IServiceManager sServiceManager;
29 | private static HashMap sCache = new HashMap();
30 |
31 | private static IServiceManager getIServiceManager() {
32 | throw new RuntimeException("Stub!!!");
33 | }
34 |
35 | /**
36 | * Returns a reference to a service with the given name.
37 | *
38 | * @param name the name of the service to get
39 | * @return a reference to the service, or null if the service doesn't exist
40 | */
41 | public static IBinder getService(String name) {
42 | throw new RuntimeException("Stub!!!");
43 | }
44 |
45 | /**
46 | * Place a new @a service called @a name into the service
47 | * manager.
48 | *
49 | * @param name the name of the new service
50 | * @param service the service object
51 | */
52 | public static void addService(String name, IBinder service) {
53 | throw new RuntimeException("Stub!!!");
54 | }
55 |
56 | /**
57 | * Place a new @a service called @a name into the service
58 | * manager.
59 | *
60 | * @param name the name of the new service
61 | * @param service the service object
62 | * @param allowIsolated set to true to allow isolated sandboxed processes
63 | * to access this service
64 | */
65 | public static void addService(String name, IBinder service, boolean allowIsolated) {
66 | throw new RuntimeException("Stub!!!");
67 | }
68 |
69 | /**
70 | * Retrieve an existing service called @a name from the
71 | * service manager. Non-blocking.
72 | */
73 | public static IBinder checkService(String name) {
74 | throw new RuntimeException("Stub!!!");
75 | }
76 |
77 | /**
78 | * Return a list of all currently running services.
79 | */
80 | public static String[] listServices() throws RemoteException {
81 | throw new RuntimeException("Stub!!!");
82 | }
83 |
84 | /**
85 | * This is only intended to be called when the process is first being brought
86 | * up and bound by the activity manager. There is only one thread in the process
87 | * at that time, so no locking is done.
88 | *
89 | * @param cache the cache of service references
90 | * @hide
91 | */
92 | public static void initServiceCache(Map cache) {
93 | throw new RuntimeException("Stub!!!");
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/android/os/SystemProperties.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2006 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 android.os;
18 |
19 | import java.util.ArrayList;
20 |
21 |
22 | /**
23 | * Gives access to the system properties store. The system properties
24 | * store contains a list of string key-value pairs.
25 | *
26 | * {@hide}
27 | */
28 | public class SystemProperties
29 | {
30 | public static final int PROP_NAME_MAX = 31;
31 | public static final int PROP_VALUE_MAX = 91;
32 |
33 | private static final ArrayList sChangeCallbacks = new ArrayList();
34 |
35 | private static native String native_get(String key);
36 | private static native String native_get(String key, String def);
37 | private static native int native_get_int(String key, int def);
38 | private static native long native_get_long(String key, long def);
39 | private static native boolean native_get_boolean(String key, boolean def);
40 | private static native void native_set(String key, String def);
41 | private static native void native_add_change_callback();
42 |
43 | /**
44 | * Get the value for the given key.
45 | * @return an empty string if the key isn't found
46 | * @throws IllegalArgumentException if the key exceeds 32 characters
47 | */
48 | public static String get(String key) {
49 | if (key.length() > PROP_NAME_MAX) {
50 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
51 | }
52 | return native_get(key);
53 | }
54 |
55 | /**
56 | * Get the value for the given key.
57 | * @return if the key isn't found, return def if it isn't null, or an empty string otherwise
58 | * @throws IllegalArgumentException if the key exceeds 32 characters
59 | */
60 | public static String get(String key, String def) {
61 | if (key.length() > PROP_NAME_MAX) {
62 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
63 | }
64 | return native_get(key, def);
65 | }
66 |
67 | /**
68 | * Get the value for the given key, and return as an integer.
69 | * @param key the key to lookup
70 | * @param def a default value to return
71 | * @return the key parsed as an integer, or def if the key isn't found or
72 | * cannot be parsed
73 | * @throws IllegalArgumentException if the key exceeds 32 characters
74 | */
75 | public static int getInt(String key, int def) {
76 | if (key.length() > PROP_NAME_MAX) {
77 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
78 | }
79 | return native_get_int(key, def);
80 | }
81 |
82 | /**
83 | * Get the value for the given key, and return as a long.
84 | * @param key the key to lookup
85 | * @param def a default value to return
86 | * @return the key parsed as a long, or def if the key isn't found or
87 | * cannot be parsed
88 | * @throws IllegalArgumentException if the key exceeds 32 characters
89 | */
90 | public static long getLong(String key, long def) {
91 | if (key.length() > PROP_NAME_MAX) {
92 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
93 | }
94 | return native_get_long(key, def);
95 | }
96 |
97 | /**
98 | * Get the value for the given key, returned as a boolean.
99 | * Values 'n', 'no', '0', 'false' or 'off' are considered false.
100 | * Values 'y', 'yes', '1', 'true' or 'on' are considered true.
101 | * (case sensitive).
102 | * If the key does not exist, or has any other value, then the default
103 | * result is returned.
104 | * @param key the key to lookup
105 | * @param def a default value to return
106 | * @return the key parsed as a boolean, or def if the key isn't found or is
107 | * not able to be parsed as a boolean.
108 | * @throws IllegalArgumentException if the key exceeds 32 characters
109 | */
110 | public static boolean getBoolean(String key, boolean def) {
111 | if (key.length() > PROP_NAME_MAX) {
112 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
113 | }
114 | return native_get_boolean(key, def);
115 | }
116 |
117 | /**
118 | * Set the value for the given key.
119 | * @throws IllegalArgumentException if the key exceeds 32 characters
120 | * @throws IllegalArgumentException if the value exceeds 92 characters
121 | */
122 | public static void set(String key, String val) {
123 | if (key.length() > PROP_NAME_MAX) {
124 | throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
125 | }
126 | if (val != null && val.length() > PROP_VALUE_MAX) {
127 | throw new IllegalArgumentException("val.length > " +
128 | PROP_VALUE_MAX);
129 | }
130 | native_set(key, val);
131 | }
132 |
133 | public static void addChangeCallback(Runnable callback) {
134 | synchronized (sChangeCallbacks) {
135 | if (sChangeCallbacks.size() == 0) {
136 | native_add_change_callback();
137 | }
138 | sChangeCallbacks.add(callback);
139 | }
140 | }
141 |
142 | static void callChangeCallbacks() {
143 | synchronized (sChangeCallbacks) {
144 | //Log.i("foo", "Calling " + sChangeCallbacks.size() + " change callbacks!");
145 | if (sChangeCallbacks.size() == 0) {
146 | return;
147 | }
148 | ArrayList callbacks = new ArrayList(sChangeCallbacks);
149 | for (int i=0; i audioDeivceList = new ArrayList<>();
53 |
54 | //sco
55 | final String bluetooth = context.getString(R.string.okbt_audiodevice_bluetooth);
56 | //听筒
57 | final String earphone = context.getString(R.string.okbt_audiodevice_earphone);
58 | //扬声器
59 | final String speaker = context.getString(R.string.okbt_audiodevice_speaker);
60 |
61 | if(OkBluetooth.isBluetoothEnable() && OkBluetooth.HFP.hasConnectedDevice()){
62 | audioDeivceList.add(bluetooth);
63 | }
64 |
65 | audioDeivceList.add(earphone);
66 | audioDeivceList.add(speaker);
67 |
68 | listView.setAdapter(new BaseAdapter() {
69 |
70 | @Override
71 | public View getView(int position, View convertView, ViewGroup parent) {
72 |
73 | String item = audioDeivceList.get(position);
74 |
75 | View view = LayoutInflater.from(context).inflate(R.layout.okbt_audio_device_list_item, null);
76 |
77 | TextView textView = (TextView) view.findViewById(R.id.okbt_audiodevice_name);
78 | textView.setText(item);
79 |
80 | return view;
81 | }
82 |
83 | @Override
84 | public long getItemId(int position) {
85 | return 0;
86 | }
87 |
88 | @Override
89 | public Object getItem(int position) {
90 | return audioDeivceList.get(position);
91 | }
92 |
93 | @Override
94 | public int getCount() {
95 | return audioDeivceList.size();
96 | }
97 | });
98 |
99 | listView.setOnItemClickListener(new OnItemClickListener() {
100 |
101 | @Override
102 | public void onItemClick(AdapterView> arg0, View arg1, int pos,
103 | long arg3) {
104 |
105 | String selected = audioDeivceList.get(pos);
106 |
107 | if(bluetooth.equals(selected)) {
108 |
109 | selectedListener.onSelected(AudioDevice.SCO);
110 |
111 | } else if(earphone.equals(selected)) {
112 |
113 | selectedListener.onSelected(AudioDevice.WIREDHEADSET);
114 |
115 | } else if(speaker.equals(selected)) {
116 |
117 | selectedListener.onSelected(AudioDevice.SPEAKER);
118 |
119 | } else {
120 |
121 | selectedListener.onSelected(AudioDevice.SBP);
122 |
123 | }
124 |
125 | dialog.dismiss();
126 |
127 | }
128 |
129 | });
130 |
131 | dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
132 | dialog.setContentView(view);
133 | dialog.show();
134 |
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/AudioService.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth;
2 |
3 | import android.content.Context;
4 | import android.media.AudioManager;
5 | import android.media.AudioSystem;
6 | import android.media.IAudioService;
7 | import android.os.RemoteException;
8 | import android.os.ServiceManager;
9 | import android.util.Log;
10 |
11 | import com.devyok.bluetooth.OkBluetooth.Interceptor;
12 | import com.devyok.bluetooth.base.BluetoothException;
13 | import com.devyok.bluetooth.base.BluetoothRuntimeException;
14 | import com.devyok.bluetooth.base.BluetoothService;
15 |
16 | import java.lang.reflect.InvocationTargetException;
17 | import java.lang.reflect.Method;
18 | /**
19 | * @author wei.deng
20 | */
21 | final class AudioService extends BluetoothService{
22 |
23 | private static final String TAG = OkBluetooth.TAG;
24 |
25 | private AudioManager mAudioManager;
26 | private IAudioService mRealAudioService;
27 | private AudioModeModifier mAudioModeModifier = AudioModeModifier.DEFAULT;
28 |
29 | /**
30 | * 实现音频模式的修改
31 | */
32 | public interface AudioModeModifier {
33 | public static final AudioModeModifier DEFAULT = new AudioModeModifier() {
34 | @Override
35 | public void modify(int audioMode) {
36 |
37 | int current = OkBluetooth.getAudioMode();
38 |
39 | if(current != audioMode){
40 | OkBluetooth.setAudioMode(audioMode);
41 | }
42 |
43 | }
44 | };
45 | public void modify(int audioMode);
46 | }
47 |
48 | @Override
49 | public boolean init() throws BluetoothException {
50 |
51 | super.init();
52 |
53 | mAudioManager = (AudioManager) OkBluetooth.getContext().getSystemService(Context.AUDIO_SERVICE);
54 | mRealAudioService = IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE));
55 |
56 | return true;
57 | }
58 |
59 | @Override
60 | public boolean destory() {
61 | super.destory();
62 |
63 | mAudioManager = null;
64 | mRealAudioService = null;
65 |
66 | return true;
67 | }
68 |
69 | public boolean connectAudio(AudioDevice audioDevice){
70 |
71 | if(audioDevice == null) throw new BluetoothRuntimeException("audioDevice null");
72 |
73 | Interceptor interceptor = OkBluetooth.getInterceptor();
74 |
75 | if(interceptor.beforeConnect(audioDevice)) {
76 | Log.i(TAG, "[AudioService] connectAudio "+audioDevice + " intercepted");
77 | return false;
78 | }
79 |
80 | if(AudioDevice.SBP == audioDevice){
81 |
82 | } else if(AudioDevice.SPEAKER == audioDevice){
83 |
84 | tryConnectSpeaker();
85 |
86 | } else if(AudioDevice.SCO == audioDevice){
87 |
88 | tryConnectSco();
89 |
90 | } else if(AudioDevice.WIREDHEADSET == audioDevice){
91 |
92 | tryConnectWiredHeadset();
93 |
94 | } else if(AudioDevice.A2DP == audioDevice){
95 |
96 | tryConnectSpeaker();
97 |
98 | }
99 |
100 | return true;
101 | }
102 |
103 | public boolean isBluetoothA2dpOn(){
104 | try {
105 | IAudioService audioService = mRealAudioService;
106 | boolean result = audioService.isBluetoothA2dpOn();
107 | return result;
108 | } catch (RemoteException e) {
109 | e.printStackTrace();
110 | Log.i(TAG, "[AudioService] isBluetoothA2dpOn on a2dp exception = " + e.getMessage());
111 | }
112 |
113 | return false;
114 | }
115 |
116 | public boolean isWiredHeadsetOn(){
117 | return mAudioManager.isWiredHeadsetOn();
118 | }
119 |
120 | public void setBluetoothA2dpOn(boolean on){
121 | try {
122 | IAudioService audioService = mRealAudioService;
123 | boolean result = audioService.isBluetoothA2dpOn();
124 | Log.i(TAG, "[AudioService] setBluetoothA2dpOn pre state = "+ result);
125 | audioService.setBluetoothA2dpOn(on);
126 | } catch (RemoteException e) {
127 | e.printStackTrace();
128 | Log.i(TAG, "[AudioService] setBluetoothA2dpOn on a2dp exception = " + e.getMessage());
129 | }
130 | }
131 |
132 | /**
133 | * 尝试连接SCO
134 | */
135 | void tryConnectSco() {
136 | boolean isPhoneCalling = OkBluetooth.isPhoneCalling();
137 | boolean isAudioConnected = OkBluetooth.HFP.isAudioConnected();
138 | boolean isBluetoothScoOn = isBluetoothScoOn();
139 | boolean isBluetoothA2dpOn = isBluetoothA2dpOn();
140 | boolean isSpeakerphoneOn = isSpeakerphoneOn();
141 |
142 | Log.i(TAG, "[AudioService] tryConnectSco isAudioConnected = " + isAudioConnected + " , isBluetoothScoOn = " + isBluetoothScoOn + " , isBluetoothA2dpOn = " + isBluetoothA2dpOn + " , isSpeakerphoneOn = " + isSpeakerphoneOn);
143 | if(!isAudioConnected) {
144 | if(!isPhoneCalling) {
145 | mAudioModeModifier.modify(AudioManager.MODE_IN_COMMUNICATION);
146 | }
147 | setSpeakerphoneOn(false);
148 | setBluetoothA2dpOn(false);
149 | setBluetoothScoOn(false);
150 | if(isPhoneCalling) {
151 | OkBluetooth.HFP.connectAudio();
152 | } else {
153 | OkBluetooth.startSco();
154 | }
155 | } else {
156 |
157 | if(isBluetoothA2dpOn){
158 | setBluetoothA2dpOn(false);
159 | }
160 | if(isSpeakerphoneOn){
161 | setSpeakerphoneOn(false);
162 | }
163 | if(!isBluetoothScoOn) {
164 | setBluetoothScoOn(true);
165 | }
166 |
167 | }
168 |
169 | }
170 |
171 | /**
172 | * 尝试连接有线耳机
173 | */
174 | void tryConnectWiredHeadset() {
175 |
176 | boolean isPhoneCalling = OkBluetooth.isPhoneCalling();
177 |
178 | boolean isAudioConnected = OkBluetooth.HFP.isAudioConnected();
179 |
180 | boolean isBluetoothScoOn = isBluetoothScoOn();
181 | boolean isBluetoothA2dpOn = isBluetoothA2dpOn();
182 | boolean isSpeakerphoneOn = isSpeakerphoneOn();
183 | if(!isPhoneCalling){
184 | mAudioModeModifier.modify(AudioManager.MODE_IN_COMMUNICATION);
185 | }
186 | Log.i(TAG, "[AudioService] tryConnectWiredHeadset isAudioConnected = " + isAudioConnected + " , isBluetoothScoOn = " + isBluetoothScoOn + " , isBluetoothA2dpOn = " + isBluetoothA2dpOn + " , isSpeakerphoneOn = " + isSpeakerphoneOn);
187 |
188 | if(isAudioConnected){
189 | outofBluetoothScoEnv();
190 | setSpeakerphoneOn(false);
191 | } else {
192 | if(OkBluetooth.isBluetoothA2dpOn()){
193 | setBluetoothA2dpOn(false);
194 | }
195 | if(OkBluetooth.isBluetoothScoOn()){
196 | setBluetoothScoOn(false);
197 | }
198 | if(OkBluetooth.isSpeakerphoneOn()){
199 | setSpeakerphoneOn(false);
200 | }
201 | }
202 | }
203 |
204 | void tryConnectSpeaker() {
205 | boolean isPhoneCalling = OkBluetooth.isPhoneCalling();
206 | boolean isAudioConnected = OkBluetooth.HFP.isAudioConnected();
207 | boolean isBluetoothScoOn = isBluetoothScoOn();
208 | boolean isBluetoothA2dpOn = isBluetoothA2dpOn();
209 | boolean isSpeakerphoneOn = isSpeakerphoneOn();
210 | if(!isPhoneCalling){
211 | mAudioModeModifier.modify(AudioManager.MODE_NORMAL);
212 | }
213 | Log.i(TAG, "[AudioService] tryConnectSpeaker isAudioConnected = " + isAudioConnected + " , isBluetoothScoOn = " + isBluetoothScoOn + " , isBluetoothA2dpOn = " + isBluetoothA2dpOn + " , isSpeakerphoneOn = " + isSpeakerphoneOn);
214 | if(isAudioConnected) {
215 | outofBluetoothScoEnv();
216 | }
217 | if(OkBluetooth.isBluetoothScoOn()){
218 | setBluetoothScoOn(false);
219 | }
220 | if(!isSpeakerphoneOn) {
221 | setSpeakerphoneOn(true);
222 | }
223 |
224 | }
225 |
226 | /**
227 | * 退出SCO
228 | * @return
229 | */
230 | private boolean outofBluetoothScoEnv(){
231 | setBluetoothA2dpOn(false);
232 | boolean result = OkBluetooth.HFP.disconnectAudio();
233 | setBluetoothScoOn(false);
234 | return result;
235 | }
236 |
237 | public void setAudioMode(int mode) {
238 | mAudioManager.setMode(mode);
239 | }
240 |
241 | public int getAudioMode(){
242 | return mAudioManager.getMode();
243 | }
244 |
245 | public void setScoStreamVolumn(int volumnIndex,int flags){
246 | mAudioManager.setStreamVolume(AudioSystem.STREAM_BLUETOOTH_SCO, (volumnIndex), flags);
247 | }
248 |
249 | public void setStreamVolumn(int streamType,int volumnIndex,int flags){
250 | mAudioManager.setStreamVolume(streamType, (volumnIndex), flags);
251 | }
252 |
253 | public int getCurrentStreamVolumn(int streamType){
254 | return mAudioManager.getStreamVolume(streamType);
255 | }
256 |
257 | public int getMaxStreamVolumn(int streamType){
258 | return mAudioManager.getStreamMaxVolume(streamType);
259 | }
260 |
261 | public int getScoStreamVolumn(){
262 | return mAudioManager.getStreamVolume(AudioSystem.STREAM_BLUETOOTH_SCO);
263 | }
264 |
265 | public int getScoMaxStreamVolumn(){
266 | return mAudioManager.getStreamMaxVolume(AudioSystem.STREAM_BLUETOOTH_SCO);
267 | }
268 |
269 | public void setSpeakerphoneOn(boolean on){
270 | mAudioManager.setSpeakerphoneOn(on);
271 | }
272 |
273 | public void setBluetoothScoOn(boolean on){
274 | mAudioManager.setBluetoothScoOn(on);
275 | }
276 |
277 | public boolean isBluetoothScoOn(){
278 | return mAudioManager.isBluetoothScoOn();
279 | }
280 |
281 | public boolean isSpeakerphoneOn(){
282 | return mAudioManager.isSpeakerphoneOn();
283 | }
284 |
285 | public void requestAudioFocusForCall(int streamType){
286 | AudioManager audioManager = mAudioManager;
287 |
288 | try {
289 | Method method = audioManager.getClass().getDeclaredMethod("requestAudioFocusForCall", new Class[]{int.class,int.class});
290 |
291 | method.invoke(audioManager, streamType,AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
292 |
293 | } catch (NoSuchMethodException e) {
294 | e.printStackTrace();
295 | } catch (SecurityException e) {
296 | e.printStackTrace();
297 | } catch (IllegalAccessException e) {
298 | // TODO Auto-generated catch block
299 | e.printStackTrace();
300 | } catch (IllegalArgumentException e) {
301 | // TODO Auto-generated catch block
302 | e.printStackTrace();
303 | } catch (InvocationTargetException e) {
304 | // TODO Auto-generated catch block
305 | e.printStackTrace();
306 | }
307 | }
308 |
309 | public void setAudioModeModifier(AudioModeModifier modifier) {
310 | this.mAudioModeModifier = (modifier != null ? modifier : AudioModeModifier.DEFAULT);
311 | }
312 |
313 | }
314 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/Configuration.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth;
2 |
3 | import com.devyok.bluetooth.OkBluetooth.ConnectionMode;
4 | import com.devyok.bluetooth.message.BluetoothMessageDispatcher;
5 | import com.devyok.bluetooth.message.BluetoothMessageHandler;
6 | import com.devyok.bluetooth.utils.BluetoothUtils;
7 |
8 | /**
9 | * @author deng.wei
10 | */
11 | public final class Configuration {
12 |
13 | public static final Configuration DEFAULT = new Builder()
14 | .setDebug(true)
15 | .setSupport(true)
16 | .setConnectionMode(ConnectionMode.BLUETOOTH_WIREDHEADSET_SPEAKER)
17 | .build();
18 |
19 | private boolean debug;
20 | private boolean isSupport;
21 | private boolean debugThread;
22 | private BluetoothMessageHandler> messageDispatcher;
23 | private boolean isSupportScoDaemon = true;
24 | private int companyid = BluetoothUtils.UNKNOW;
25 | private ConnectionMode connectionMode = ConnectionMode.BLUETOOTH_WIREDHEADSET_SPEAKER;
26 | private int forceTypes;
27 | private Configuration(){}
28 |
29 | public boolean isDebugThread() {
30 | return debugThread;
31 | }
32 |
33 | public int getForceTypes(){
34 | return forceTypes;
35 | }
36 |
37 | public ConnectionMode getConnectionMode(){
38 | return connectionMode;
39 | }
40 |
41 | public int getCompanyId(){
42 | return this.companyid;
43 | }
44 |
45 | public boolean isSupportScoDaemon(){
46 | return isSupportScoDaemon;
47 | }
48 |
49 | public boolean isSupport() {
50 | return isSupport;
51 | }
52 |
53 | public boolean isDebug() {
54 | return debug;
55 | }
56 |
57 | public BluetoothMessageHandler getDispatcher(){
58 | return (BluetoothMessageHandler) this.messageDispatcher;
59 | }
60 |
61 | @Override
62 | public String toString(){
63 | StringBuffer buffer = new StringBuffer();
64 |
65 | buffer.append("Configuration { ");
66 | buffer.append("debug").append("=").append(debug).append(",")
67 | .append("isSupport").append("=").append(isSupport).append(",")
68 | .append("debugThread").append("=").append(debugThread).append(",")
69 | .append("messageDispatcher").append("=").append(messageDispatcher).append(",")
70 | .append("isSupportScoDaemon").append("=").append(isSupportScoDaemon).append(",")
71 | .append("companyid").append("=").append(companyid).append(",")
72 | .append("connectionMode").append("=").append(connectionMode).append(",")
73 | .append("forceTypes").append("=").append(forceTypes).append(",")
74 | .append("hasForcePhoneIdle").append("=").append((forceTypes & OkBluetooth.FORCE_TYPE_PHONE_INCALL_TO_IDLE)!=0 ? "Y" : "N").append(",")
75 | .append("hasForcePhoneIncall").append("=").append((forceTypes & OkBluetooth.FORCE_TYPE_PHONE_INCALL)!=0 ? "Y" : "N").append(",")
76 | .append("hasForcePhoneRing").append("=").append((forceTypes & OkBluetooth.FORCE_TYPE_PHONE_RING)!=0 ? "Y" : "N");
77 | buffer.append(" }");
78 |
79 | return buffer.toString();
80 | }
81 |
82 | public static class Builder {
83 |
84 | private boolean debug;
85 | private boolean isSupportBMS;
86 | private boolean debugThread;
87 | private int companyid;
88 | private BluetoothMessageHandler> messageDispatcher;
89 | private ConnectionMode connectionMode;
90 | private int forceTypes;
91 |
92 | public Builder(){
93 | }
94 |
95 | public Builder setForceTypes(int forceTypes){
96 | this.forceTypes = forceTypes;
97 | return this;
98 | }
99 |
100 | public Builder setCompanyId(int companyid) {
101 | this.companyid = companyid;
102 | return this;
103 | }
104 |
105 | public Builder setConnectionMode(ConnectionMode mode) {
106 | this.connectionMode = mode;
107 | return this;
108 | }
109 |
110 | public Builder setDebug(boolean debug) {
111 | this.debug = debug;
112 | return this;
113 | }
114 |
115 | public Builder setSupport(boolean isSupport) {
116 | this.isSupportBMS = isSupport;
117 | return this;
118 | }
119 |
120 | public Builder setDebugThread(boolean debugThread) {
121 | this.debugThread = debugThread;
122 | return this;
123 | }
124 |
125 | public Builder setMessageDispatcher(BluetoothMessageHandler dispatch){
126 | messageDispatcher = dispatch;
127 | return this;
128 | }
129 |
130 | public Configuration build(){
131 | Configuration configuration = new Configuration();
132 |
133 | configuration.debug = this.debug;
134 | configuration.debugThread = this.debugThread;
135 | configuration.isSupport = this.isSupportBMS;
136 | configuration.messageDispatcher = this.messageDispatcher;
137 | configuration.companyid = this.companyid;
138 | configuration.connectionMode = this.connectionMode;
139 | configuration.forceTypes = this.forceTypes;
140 |
141 | if(configuration.messageDispatcher == null){
142 | configuration.messageDispatcher = BluetoothMessageDispatcher.getDispatcher();
143 | }
144 |
145 | return configuration;
146 | }
147 |
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/TelephonyService.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth;
2 |
3 | import android.content.Context;
4 | import android.telephony.PhoneStateListener;
5 | import android.telephony.TelephonyManager;
6 | import android.util.Log;
7 |
8 | import com.devyok.bluetooth.ConnectionHelper.Event;
9 | import com.devyok.bluetooth.base.BluetoothException;
10 | import com.devyok.bluetooth.base.BluetoothService;
11 | /**
12 | *
13 | * @author wei.deng
14 | */
15 | final class TelephonyService extends BluetoothService{
16 |
17 | private static final String TAG = OkBluetooth.TAG;
18 |
19 | private boolean isListenPhoneState = true;
20 |
21 | /**
22 | * 负责监听系统电话状态,当系统电话挂断,则尝试提交恢复音频等连接的请求
23 | */
24 | private volatile PhoneStateListenerImpl phoneStateListenerImpl;
25 | private TelephonyManager mTelephonyManager;
26 |
27 | public TelephonyService(){
28 | this(true);
29 | }
30 |
31 | public TelephonyService(boolean isListenPhoneState){
32 | this.isListenPhoneState = isListenPhoneState;
33 | }
34 |
35 | @Override
36 | public boolean init() throws BluetoothException {
37 | super.init();
38 | mTelephonyManager = (TelephonyManager) OkBluetooth.getContext().getSystemService(Context.TELEPHONY_SERVICE);
39 | listenPhoneState();
40 |
41 | return true;
42 | }
43 |
44 | @Override
45 | public boolean destory() {
46 | super.destory();
47 | unlistenPhoneState();
48 | return true;
49 | }
50 |
51 | private void listenPhoneState() {
52 | if(isListenPhoneState && phoneStateListenerImpl == null){
53 | phoneStateListenerImpl = new PhoneStateListenerImpl();
54 | mTelephonyManager.listen(phoneStateListenerImpl,PhoneStateListener.LISTEN_CALL_STATE);
55 | }
56 | }
57 |
58 | private void unlistenPhoneState() {
59 | if(isListenPhoneState && phoneStateListenerImpl != null){
60 | mTelephonyManager.listen(phoneStateListenerImpl,PhoneStateListener.LISTEN_NONE);
61 | phoneStateListenerImpl = null;
62 | }
63 | }
64 |
65 | public boolean isPhoneCalling() {
66 | int callState = mTelephonyManager.getCallState();
67 | if(callState == TelephonyManager.CALL_STATE_OFFHOOK || callState == TelephonyManager.CALL_STATE_RINGING){
68 | return true;
69 | }
70 | return false;
71 | }
72 |
73 | class PhoneStateListenerImpl extends PhoneStateListener {
74 |
75 | volatile boolean called = false;
76 |
77 | @Override
78 | public void onCallStateChanged(int state, String incomingNumber) {
79 |
80 | switch (state) {
81 | case TelephonyManager.CALL_STATE_IDLE:
82 | Log.i(TAG, "[TelephonyService] call idle");
83 | try {
84 | if(called && OkBluetooth.hasForcePhoneIdle()){
85 | OkBluetooth.tryRecoveryAudioConnection(Event.PHONECALL_INCALL_TO_IDLE);
86 | }
87 | } finally {
88 | called = false;
89 | }
90 |
91 | break;
92 | case TelephonyManager.CALL_STATE_RINGING:
93 | case TelephonyManager.CALL_STATE_OFFHOOK:
94 | Log.i(TAG, "[TelephonyService] system phone calling");
95 | called = true;
96 | break;
97 | }
98 | }
99 | }
100 |
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/a2dp/A2dpProfileService.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.a2dp;
2 |
3 | import android.bluetooth.BluetoothA2dp;
4 | import android.bluetooth.BluetoothDevice;
5 | import android.bluetooth.BluetoothProfile;
6 | import android.bluetooth.BluetoothUuid;
7 | import android.os.ParcelUuid;
8 |
9 | import com.devyok.bluetooth.base.BluetoothProfileService;
10 | import com.devyok.bluetooth.base.BluetoothProfileServiceTemplate;
11 | import com.devyok.bluetooth.base.BluetoothRuntimeException;
12 | /**
13 | * @author wei.deng
14 | */
15 | public class A2dpProfileService extends BluetoothProfileServiceTemplate implements BluetoothA2dpProfileService{
16 | //copy from 5.0 settings
17 | public static final ParcelUuid[] SINK_UUIDS = {
18 | BluetoothUuid.AudioSink,
19 | BluetoothUuid.AdvAudioDist,
20 | };
21 |
22 | public static final int PROFILE = BluetoothProfile.A2DP;
23 |
24 | public A2dpProfileService() {
25 | super(PROFILE);
26 | }
27 |
28 | public A2dpProfileService(BluetoothProfileService decorater) {
29 | super(PROFILE,decorater);
30 | }
31 |
32 | public A2dpProfileService(int profileType) {
33 | super(profileType);
34 | throw new BluetoothRuntimeException("not support");
35 | }
36 |
37 | @Override
38 | public boolean isA2dpPlaying(final BluetoothDevice device) {
39 |
40 | if(realService == null) return false;
41 |
42 | return ((BluetoothA2dp)realService).isA2dpPlaying(device);
43 |
44 | }
45 |
46 | @Override
47 | protected ConnectionStateListenerArgs make() {
48 | return new ConnectionStateListenerArgs() {
49 |
50 | @Override
51 | public String extraPreState() {
52 | return BluetoothA2dp.EXTRA_PREVIOUS_STATE;
53 | }
54 |
55 | @Override
56 | public String extraNewState() {
57 | return BluetoothA2dp.EXTRA_STATE;
58 | }
59 |
60 | @Override
61 | public String extraDevice() {
62 | return BluetoothDevice.EXTRA_DEVICE;
63 | }
64 |
65 | @Override
66 | public String action() {
67 | return BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED;
68 | }
69 | };
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/a2dp/BluetoothA2dpProfileService.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.a2dp;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 |
5 | import com.devyok.bluetooth.base.BluetoothProfileService;
6 | /**
7 | *
8 | * @author wei.deng
9 | *
10 | */
11 | public interface BluetoothA2dpProfileService extends BluetoothProfileService{
12 |
13 | public boolean isA2dpPlaying(BluetoothDevice device);
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/BaseBluetoothStateChangedListener.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.IntentFilter;
7 |
8 | import com.devyok.bluetooth.OkBluetooth;
9 | /**
10 | * @author wei.deng
11 | */
12 | public abstract class BaseBluetoothStateChangedListener extends BroadcastReceiver{
13 |
14 | private volatile boolean mCalled;
15 |
16 | public BaseBluetoothStateChangedListener(){
17 | }
18 |
19 | public abstract boolean onChanged(StateInformation information);
20 | public abstract String[] actions();
21 |
22 | void check(){
23 |
24 | }
25 |
26 | public boolean isStarted() {
27 | return mCalled;
28 | }
29 |
30 | public void startListener() throws BluetoothException {
31 |
32 | check();
33 | String[] actions = actions();
34 |
35 | if(actions == null || actions.length == 0){
36 | throw new BluetoothException("listener actions is empty");
37 | }
38 |
39 | synchronized (this) {
40 | IntentFilter stateFilter = new IntentFilter();
41 | for(int i = 0;i < actions.length;i++){
42 | stateFilter.addAction(actions[i]);
43 | }
44 | OkBluetooth.getContext().registerReceiver(this, stateFilter);
45 | mCalled = true;
46 | }
47 | }
48 |
49 | public void stopListener() {
50 |
51 | check();
52 | synchronized (this) {
53 | if (isStarted()) {
54 | try {
55 | OkBluetooth.getContext().unregisterReceiver(this);
56 | } finally {
57 | recycle();
58 | }
59 | }
60 | }
61 | }
62 |
63 | @Override
64 | public void onReceive(Context context, Intent intent) {
65 |
66 | StateInformation information = StateInformation.toInformation(intent);
67 |
68 | onChanged(information);
69 |
70 | }
71 |
72 | public void recycle(){
73 | mCalled = false;
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/BluetoothAdapterService.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 |
3 | import android.bluetooth.BluetoothA2dp;
4 | import android.bluetooth.BluetoothAdapter;
5 | import android.bluetooth.BluetoothDevice;
6 | import android.bluetooth.BluetoothHeadset;
7 | import android.bluetooth.BluetoothProfile;
8 | import android.bluetooth.BluetoothProfile.ServiceListener;
9 | import android.os.Build;
10 | import android.util.Log;
11 |
12 | import com.devyok.bluetooth.OkBluetooth;
13 | import com.devyok.bluetooth.OkBluetooth.Callback2;
14 | import com.devyok.bluetooth.utils.BluetoothUtils;
15 |
16 | import java.lang.reflect.InvocationTargetException;
17 | import java.lang.reflect.Method;
18 | import java.util.List;
19 | import java.util.Set;
20 | /**
21 | * @author deng.wei
22 | */
23 | public class BluetoothAdapterService extends BluetoothService{
24 |
25 | private static String TAG = BluetoothAdapterService.class.getSimpleName();
26 |
27 | private BluetoothAdapterStateListener mAdapterStateListener = BluetoothAdapterStateListener.EMPTY;
28 | private final BluetoothAdapterStateListenerImpl mAdapterStateListenerImpl = new BluetoothAdapterStateListenerImpl();
29 |
30 | public BluetoothAdapterService(){
31 | }
32 |
33 | public int getProfileConnectionState(int profile) {
34 | return BluetoothAdapter.getDefaultAdapter().getProfileConnectionState(profile);
35 | }
36 |
37 | @Override
38 | public boolean init() throws BluetoothException {
39 | super.init();
40 | mAdapterStateListenerImpl.startListener();
41 | return true;
42 | }
43 |
44 | @Override
45 | public boolean destory() {
46 | super.destory();
47 | mAdapterStateListenerImpl.stopListener();
48 | mAdapterStateListener = null;
49 | return true;
50 | }
51 |
52 | public int getConnectionState() {
53 |
54 | BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
55 |
56 | try {
57 | Method m = adapter.getClass().getDeclaredMethod("getConnectionState", null);
58 |
59 | try {
60 | Object result = m.invoke(adapter, null);
61 |
62 | if(result!=null){
63 | return Integer.valueOf(result.toString());
64 | }
65 |
66 | } catch (IllegalAccessException | IllegalArgumentException
67 | | InvocationTargetException e) {
68 | e.printStackTrace();
69 | }
70 |
71 | } catch (NoSuchMethodException | SecurityException e) {
72 | e.printStackTrace();
73 | }
74 |
75 | return BluetoothAdapter.STATE_DISCONNECTED;
76 | }
77 |
78 | public Set getBondedDevices(){
79 | return BluetoothAdapter.getDefaultAdapter().getBondedDevices();
80 | }
81 |
82 | public void setBluetoothAdapterStateListener(BluetoothAdapterStateListener lis){
83 | this.mAdapterStateListener = (lis!=null ? lis : BluetoothAdapterStateListener.EMPTY);
84 | }
85 |
86 | /**
87 | * 打开蓝牙
88 | */
89 | public void enable(){
90 | BluetoothAdapter.getDefaultAdapter().enable();
91 | }
92 |
93 | public void closeBluetoothProfile(int profile,BluetoothProfile bluetoothProfile) {
94 | if(bluetoothProfile==null) return ;
95 | BluetoothAdapter.getDefaultAdapter().closeProfileProxy(profile, bluetoothProfile);
96 | }
97 |
98 | public void closeBluetoothProfile(BluetoothProfile bluetoothProfile) {
99 | if(bluetoothProfile==null) return ;
100 | if (bluetoothProfile instanceof BluetoothA2dp) {
101 | closeBluetoothProfile(BluetoothProfile.A2DP,bluetoothProfile);
102 | } else if (bluetoothProfile instanceof BluetoothHeadset) {
103 | closeBluetoothProfile(BluetoothProfile.HEADSET,bluetoothProfile);
104 | }
105 | }
106 |
107 | public boolean isEnable(){
108 | return BluetoothAdapter.getDefaultAdapter().isEnabled();
109 | }
110 |
111 | public boolean disable(){
112 | return BluetoothAdapter.getDefaultAdapter().disable();
113 | }
114 |
115 | public boolean getProfileService(final int profileParam,final ServiceListener serviceListener){
116 |
117 | boolean result = BluetoothAdapter.getDefaultAdapter().getProfileProxy(OkBluetooth.getContext(), new ServiceListener() {
118 |
119 | @Override
120 | public void onServiceDisconnected(int profile) {
121 |
122 | if(serviceListener!=null){
123 | serviceListener.onServiceDisconnected(profile);
124 | }
125 |
126 | }
127 |
128 | public void onServiceConnected(int profile, BluetoothProfile proxy) {
129 |
130 | if(serviceListener!=null){
131 | serviceListener.onServiceConnected(profile, proxy);
132 | }
133 |
134 | }
135 | }, profileParam);
136 |
137 | return result;
138 | }
139 |
140 | public void getConnectedBluetoothDevice(final int profileParam,
141 | final Callback2> serviceConnectedCallback){
142 |
143 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
144 |
145 | boolean result = getProfileService(profileParam, new ServiceListener() {
146 |
147 | void handleCallback(BluetoothProfile profile,List list) {
148 | if(serviceConnectedCallback!=null){
149 | serviceConnectedCallback.callback(profile, list);
150 | }
151 | }
152 |
153 | @Override
154 | public void onServiceDisconnected(int profile) {
155 |
156 | Log.i(TAG, "[devybt connect] getConnectedBluetoothDevice BluetoothProfile("+BluetoothUtils.getProfileString(profile)+") onServiceDisconnected()");
157 |
158 | if(serviceConnectedCallback!=null){
159 | serviceConnectedCallback.callback(null, null);
160 | }
161 |
162 | }
163 |
164 | public void onServiceConnected(int profile, BluetoothProfile proxy) {
165 | try {
166 | switch (profile) {
167 | case BluetoothProfile.A2DP:
168 | case BluetoothProfile.HEADSET:
169 |
170 | Log.i(TAG, "[devybt connect] getConnectedBluetoothDevice BluetoothProfile("+BluetoothUtils.getProfileString(profile)+") onServiceConnected()");
171 |
172 | List connectedDevices = proxy.getConnectedDevices();
173 |
174 | Log.i(TAG, "[devybt connect] getConnectedBluetoothDevice BluetoothProfile("+BluetoothUtils.getProfileString(profile)+") connectedDevices(size = "+connectedDevices.size()+")");
175 |
176 | handleCallback(proxy,connectedDevices);
177 |
178 | break;
179 | case BluetoothProfile.HEALTH:
180 | Log.i(TAG, "[devybt connect] BluetoothProfile.HEALTH onServiceConnected()");
181 | handleCallback(null,null);
182 | break;
183 | default:
184 | Log.i(TAG, "[devybt connect] BluetoothProfile.default onServiceConnected()");
185 | handleCallback(null,null);
186 | break;
187 | }
188 |
189 | } catch(Exception e){
190 | handleCallback(null,null);
191 | }
192 |
193 | }
194 | });
195 |
196 |
197 | if(!result){ //get error , notify
198 | if(serviceConnectedCallback!=null){
199 | serviceConnectedCallback.callback(null, null);
200 | }
201 | }
202 |
203 | Log.i(TAG, "[devybt connect] BluetoothProfile.getProfileProxy() result = " + result);
204 |
205 | } else {
206 | if(serviceConnectedCallback!=null){
207 | serviceConnectedCallback.callback(null, null);
208 | }
209 | }
210 |
211 | }
212 |
213 | private class BluetoothAdapterStateListenerImpl extends BaseBluetoothStateChangedListener {
214 |
215 | public BluetoothAdapterStateListenerImpl() {
216 | }
217 |
218 | @Override
219 | public boolean onChanged(StateInformation information) {
220 |
221 | if(OkBluetooth.isDebugable()) {
222 | BluetoothUtils.dumpBluetoothSystemSwitchStateInfos(TAG, information.getIntent());
223 | }
224 |
225 | int currentState = information.getCurrentState();
226 |
227 | switch (currentState) {
228 | case BluetoothAdapter.STATE_TURNING_ON:
229 | mAdapterStateListener.onOpening(information);
230 | break;
231 | case BluetoothAdapter.STATE_ON:
232 | mAdapterStateListener.onOpened(information);
233 | break;
234 | case BluetoothAdapter.STATE_TURNING_OFF:
235 | mAdapterStateListener.onCloseing(information);
236 | break;
237 | case BluetoothAdapter.STATE_OFF:
238 | mAdapterStateListener.onClosed(information);
239 | break;
240 | default:
241 | break;
242 | }
243 |
244 | return true;
245 | }
246 |
247 | @Override
248 | public String[] actions() {
249 | return new String[]{BluetoothAdapter.ACTION_STATE_CHANGED};
250 | }
251 |
252 | }
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 | }
261 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/BluetoothAdapterStateListener.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 |
3 | /**
4 | * @author deng.wei
5 | */
6 | public abstract class BluetoothAdapterStateListener{
7 |
8 | public static final BluetoothAdapterStateListener EMPTY = new BluetoothAdapterStateListener() {};
9 |
10 | /**
11 | * 正在开启
12 | */
13 | public void onOpening(StateInformation stateInformation){}
14 | /**
15 | * 已开启
16 | */
17 | public void onOpened(StateInformation stateInformation){}
18 | /**
19 | * 关闭中
20 | */
21 | public void onCloseing(StateInformation stateInformation){}
22 | /**
23 | * 已关闭
24 | */
25 | public void onClosed(StateInformation stateInformation){}
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/BluetoothAndroidThread.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 |
3 |
4 | import android.os.Handler;
5 | import android.os.HandlerThread;
6 |
7 | /**
8 | * @author deng.wei
9 | */
10 | public final class BluetoothAndroidThread extends HandlerThread implements Executor{
11 | private static BluetoothAndroidThread sInstance;
12 | private static Handler sHandler;
13 |
14 | private BluetoothAndroidThread() {
15 | super("bt.runtime.base", android.os.Process.THREAD_PRIORITY_DEFAULT);
16 | }
17 |
18 | private static void ensureThreadLocked() {
19 | if (sInstance == null) {
20 | sInstance = new BluetoothAndroidThread();
21 | sInstance.start();
22 | sHandler = new Handler(sInstance.getLooper());
23 | }
24 | }
25 |
26 | public static BluetoothAndroidThread get() {
27 | synchronized (BluetoothAndroidThread.class) {
28 | ensureThreadLocked();
29 | return sInstance;
30 | }
31 | }
32 |
33 | static Handler getHandler() {
34 | synchronized (BluetoothAndroidThread.class) {
35 | ensureThreadLocked();
36 | return sHandler;
37 | }
38 | }
39 |
40 | public boolean execute(Runnable runnable) {
41 | if(runnable!=null){
42 | synchronized (BluetoothAndroidThread.class) {
43 | getHandler().post(runnable);
44 | }
45 | return true;
46 | }
47 | return false;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/BluetoothException.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 | /**
3 | *
4 | * @author wei.deng
5 | *
6 | */
7 | public class BluetoothException extends Exception{
8 |
9 | /**
10 | *
11 | */
12 | private static final long serialVersionUID = 1L;
13 |
14 | public BluetoothException(String message, Throwable cause) {
15 | super(message, cause);
16 | }
17 |
18 | public BluetoothException(String message) {
19 | super(message);
20 | }
21 |
22 | public BluetoothException(Throwable cause) {
23 | super(cause);
24 | }
25 |
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/BluetoothProfileService.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 |
3 | import java.util.List;
4 |
5 | import android.bluetooth.BluetoothDevice;
6 | import android.bluetooth.BluetoothProfile;
7 | /**
8 | * @author wei.deng
9 | */
10 | public interface BluetoothProfileService extends BluetoothServiceLifecycle{
11 |
12 | public interface BluetoothProfileServiceStateListener {
13 | public static final BluetoothProfileServiceStateListener EMPTY = new BluetoothProfileServiceStateListener(){
14 | @Override
15 | public void onServiceReady(int profile,BluetoothProfileService service) {
16 | }
17 | };
18 | public void onServiceReady(int profile, BluetoothProfileService service);
19 | }
20 |
21 | public interface BluetoothProfileConnectionStateChangedListener {
22 |
23 | public static final BluetoothProfileConnectionStateChangedListener EMPTY = new BluetoothProfileConnectionStateChangedListener() {
24 | @Override
25 | public void onDisconnected(int profile, int newState, int preState,
26 | BluetoothDevice device) {
27 | }
28 | @Override
29 | public void onConnected(int profile, int newState, int preState,
30 | BluetoothDevice device) {
31 | }
32 | };
33 |
34 | public void onConnected(int profile, int newState, int preState, BluetoothDevice device);
35 | public void onDisconnected(int profile, int newState, int preState, BluetoothDevice device);
36 | }
37 |
38 | public void registerProfileConnectionStateChangedListener(BluetoothProfileConnectionStateChangedListener lis);
39 | public void unregisterProfileConnectionStateChangedListener(BluetoothProfileConnectionStateChangedListener lis);
40 |
41 | public void registerBluetoothProfileServiceListener(BluetoothProfileServiceStateListener lis);
42 | public void unregisterBluetoothProfileServiceListener(BluetoothProfileServiceStateListener lis);
43 |
44 | /**
45 | * DISCONNECTED��ordinal��{@link BluetoothProfile#STATE_DISCONNECTED}��ֵ�Ƕ�Ӧ��,����˳���ܱ�,��������������
46 | */
47 | public enum ProfileConnectionState {
48 | DISCONNECTED,
49 | CONNECTING,
50 | CONNECTED,
51 | DISCONNECTING,
52 | CONNECTED_NO_PHONE,
53 | CONNECTED_NO_MEDIA,
54 | CONNECTED_NO_PHONE_AND_MEIDA;
55 |
56 | public static ProfileConnectionState toState(int state) {
57 |
58 | ProfileConnectionState[] states = ProfileConnectionState.values();
59 |
60 | for(ProfileConnectionState item : states){
61 | if(item.ordinal() == state){
62 | return item;
63 | }
64 | }
65 |
66 | return ProfileConnectionState.DISCONNECTED;
67 | }
68 |
69 | public static boolean isConnected(ProfileConnectionState state) {
70 |
71 | switch (state) {
72 | case CONNECTED:
73 | case CONNECTED_NO_PHONE:
74 | case CONNECTED_NO_MEDIA:
75 | case CONNECTED_NO_PHONE_AND_MEIDA:
76 | return true;
77 | }
78 |
79 | return false;
80 | }
81 | }
82 |
83 |
84 | public ProfileConnectionState getConnectionState(final BluetoothDevice device);
85 |
86 | public ProfileConnectionState getCurrentConnectionState();
87 |
88 | public List getConnectedBluetoothDeviceList();
89 |
90 |
91 | public List getConnectedBluetoothDeviceList(final String deviceName);
92 | /**
93 | * ��android4.2�Ļ��������Ͽ��ɹ�֮�Ὣ���ȼ�����ΪON����ô�����������������Զ�����
94 | * ����5.0��������
95 | *
96 | */
97 | public boolean disconnect(final BluetoothDevice device) ;
98 | /**
99 | * android�汾���� 4.4֮��,����a2dpʧ�ܣ��׳�Ȩ���쳣��android.permission.WRITE_SECURE_SETTINGS(ϵͳ��)
100 | * �Ͽ�û����
101 | */
102 | public boolean connect(final BluetoothDevice device) ;
103 |
104 | public int getPriority(final BluetoothDevice device);
105 | /**
106 | * android�汾���� 4.4֮��,setPriorityʧ�ܣ��׳�Ȩ���쳣��android.permission.WRITE_SECURE_SETTINGS(ϵͳ��)
107 | * @param priority
108 | * @param device
109 | * @return
110 | */
111 | public boolean setPriority(final int priority, final BluetoothDevice device);
112 |
113 | public static final BluetoothProfileService EMPTY = new BluetoothProfileService() {
114 |
115 | @Override
116 | public void registerProfileConnectionStateChangedListener(
117 | BluetoothProfileConnectionStateChangedListener lis) {
118 | // TODO Auto-generated method stub
119 |
120 | }
121 |
122 | @Override
123 | public void unregisterProfileConnectionStateChangedListener(
124 | BluetoothProfileConnectionStateChangedListener lis) {
125 | // TODO Auto-generated method stub
126 |
127 | }
128 |
129 | @Override
130 | public ProfileConnectionState getConnectionState(BluetoothDevice device) {
131 | // TODO Auto-generated method stub
132 | return null;
133 | }
134 |
135 | @Override
136 | public ProfileConnectionState getCurrentConnectionState() {
137 | // TODO Auto-generated method stub
138 | return null;
139 | }
140 |
141 | @Override
142 | public List getConnectedBluetoothDeviceList() {
143 | // TODO Auto-generated method stub
144 | return null;
145 | }
146 |
147 | @Override
148 | public List getConnectedBluetoothDeviceList(
149 | String deviceName) {
150 | // TODO Auto-generated method stub
151 | return null;
152 | }
153 |
154 | @Override
155 | public boolean disconnect(BluetoothDevice device) {
156 | // TODO Auto-generated method stub
157 | return false;
158 | }
159 |
160 | @Override
161 | public boolean connect(BluetoothDevice device) {
162 | // TODO Auto-generated method stub
163 | return false;
164 | }
165 |
166 | @Override
167 | public int getPriority(BluetoothDevice device) {
168 | // TODO Auto-generated method stub
169 | return 0;
170 | }
171 |
172 | @Override
173 | public boolean setPriority(int priority, BluetoothDevice device) {
174 | // TODO Auto-generated method stub
175 | return false;
176 | }
177 |
178 | @Override
179 | public void registerBluetoothProfileServiceListener(
180 | BluetoothProfileServiceStateListener lis) {
181 | }
182 |
183 | @Override
184 | public void unregisterBluetoothProfileServiceListener(
185 | BluetoothProfileServiceStateListener lis) {
186 | }
187 |
188 | @Override
189 | public boolean init() throws BluetoothException {
190 | return false;
191 | }
192 |
193 | @Override
194 | public boolean destory() {
195 | return false;
196 | }};
197 |
198 | }
199 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/BluetoothRuntimeException.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 | /**
3 | * @author deng.wei
4 | */
5 | public class BluetoothRuntimeException extends RuntimeException{
6 |
7 | /**
8 | *
9 | */
10 | private static final long serialVersionUID = 1L;
11 |
12 | public BluetoothRuntimeException(String detailMessage, Throwable throwable) {
13 | super(detailMessage, throwable);
14 | // TODO Auto-generated constructor stub
15 | }
16 |
17 | public BluetoothRuntimeException(String detailMessage) {
18 | super(detailMessage);
19 | // TODO Auto-generated constructor stub
20 | }
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/BluetoothService.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 | /**
3 | * @author deng.wei
4 | */
5 | //adapter
6 | public abstract class BluetoothService implements BluetoothServiceLifecycle{
7 |
8 | public boolean init() throws BluetoothException{
9 |
10 | return false;
11 | }
12 |
13 | public boolean destory(){
14 | return false;
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/BluetoothServiceLifecycle.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 | /**
3 | * @author wei.deng
4 | */
5 | public interface BluetoothServiceLifecycle {
6 |
7 | public boolean init() throws BluetoothException;
8 |
9 | public boolean destory();
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/Executor.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 | /**
3 | * @author deng.wei
4 | */
5 | public interface Executor {
6 | public boolean execute(Runnable task);
7 | }
8 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/StateInformation.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 |
3 | import android.bluetooth.BluetoothAdapter;
4 | import android.bluetooth.BluetoothDevice;
5 | import android.content.Intent;
6 |
7 | import com.devyok.bluetooth.utils.BluetoothUtils;
8 | /**
9 | * @author wei.deng
10 | */
11 | public final class StateInformation {
12 |
13 | static final StateInformation EMPTY = new StateInformation();
14 |
15 | private int currentState = BluetoothUtils.UNKNOW;
16 | private int previousState = BluetoothUtils.UNKNOW;
17 | private BluetoothDevice device;
18 | private String broadcastAction = BluetoothUtils.EMPTY_STRING;
19 | private Intent intent;
20 |
21 | private StateInformation(){
22 | }
23 |
24 | public boolean isUnknow(){
25 | return (currentState == BluetoothUtils.UNKNOW || previousState == BluetoothUtils.UNKNOW);
26 | }
27 |
28 | public boolean isEmpty(){
29 | return (this == EMPTY) || (isUnknow());
30 | }
31 |
32 | public static StateInformation toInformation(Intent intent){
33 |
34 | if(intent == null) return StateInformation.EMPTY;
35 |
36 | int currentState = BluetoothUtils.UNKNOW;
37 | if(intent.hasExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE)){
38 | currentState = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, BluetoothUtils.UNKNOW);
39 | }
40 |
41 | int previousState = BluetoothUtils.UNKNOW;
42 |
43 | if(intent.hasExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE)) {
44 | previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, BluetoothUtils.UNKNOW);
45 | }
46 |
47 | BluetoothDevice device = null;
48 | if(intent.hasExtra(BluetoothDevice.EXTRA_DEVICE)) {
49 | device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
50 | }
51 |
52 | String broadcastAction = intent.getAction();
53 | return obtain(currentState, previousState, device, broadcastAction,intent);
54 | }
55 |
56 | public static StateInformation obtain(int currentState,int previousState,BluetoothDevice device,String broadcastAction,Intent intent){
57 |
58 | StateInformation information = new StateInformation();
59 |
60 | information.currentState = currentState;
61 | information.previousState = previousState;
62 | information.device = device;
63 | information.broadcastAction = broadcastAction;
64 | information.intent = intent;
65 |
66 | return information;
67 | }
68 |
69 | public int getCurrentState() {
70 | return currentState;
71 | }
72 |
73 | public BluetoothDevice getDevice() {
74 | return device;
75 | }
76 |
77 | public String getBroadcastAction() {
78 | return broadcastAction;
79 | }
80 |
81 | public int getPreviousState() {
82 | return previousState;
83 | }
84 |
85 | public Intent getIntent() {
86 | return intent;
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/base/TaskQueue.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.base;
2 |
3 | import java.util.Iterator;
4 | import java.util.Map;
5 | import java.util.concurrent.ConcurrentHashMap;
6 |
7 | import android.os.Handler;
8 | import android.os.Handler.Callback;
9 | import android.os.HandlerThread;
10 | /**
11 | * @author wei.deng
12 | */
13 | public final class TaskQueue extends HandlerThread{
14 | private Handler mHandler;
15 |
16 | final ConcurrentHashMap taskMapping = new ConcurrentHashMap();
17 |
18 | public TaskQueue(String name) {
19 | this(name,null);
20 | }
21 |
22 | public TaskQueue(String name,Callback callback) {
23 | super(name, android.os.Process.THREAD_PRIORITY_DEFAULT);
24 | ensureThreadLocked(callback);
25 | }
26 |
27 | void ensureThreadLocked(Callback callback) {
28 | start();
29 | mHandler = new Handler(getLooper(),callback);
30 | }
31 |
32 | void remove(TaskWrapper taskWrapper){
33 | getHandler().removeCallbacks(taskWrapper);
34 | if(taskWrapper.taskImpl!=null){
35 | taskMapping.remove(taskWrapper.taskImpl);
36 | taskWrapper.taskImpl = null;
37 | }
38 | }
39 |
40 | private Handler getHandler() {
41 | return mHandler;
42 | }
43 |
44 | public boolean contains(Runnable task){
45 | return taskMapping.contains(task);
46 | }
47 |
48 | public void removeTasks(Runnable ...tasks){
49 |
50 | for (int i = 0; i < tasks.length; i++) {
51 | Runnable task = tasks[i];
52 | if(task == null) continue;
53 | TaskWrapper taskWrapper = taskMapping.remove(task);
54 | if(taskWrapper!=null){
55 | taskWrapper.taskImpl = null;
56 | getHandler().removeCallbacks(taskWrapper);
57 | }
58 | }
59 |
60 | }
61 |
62 | public void removeAllTasks(){
63 |
64 | for(Iterator> iter = taskMapping.entrySet().iterator();iter.hasNext();){
65 |
66 | Map.Entry item = iter.next();
67 |
68 | TaskWrapper taskWrapper = item.getValue();
69 | taskWrapper.taskImpl = null;
70 | getHandler().removeCallbacks(taskWrapper);
71 |
72 | }
73 |
74 | taskMapping.clear();
75 |
76 | }
77 |
78 | public void submitTask(Runnable task){
79 | TaskWrapper taskWrapper = TaskWrapper.create(task, this);
80 | taskMapping.put(task, taskWrapper);
81 | getHandler().post(taskWrapper);
82 | }
83 |
84 | public void submitTask(Runnable task,long delayMillis){
85 | TaskWrapper taskWrapper = TaskWrapper.create(task, this);
86 | taskMapping.put(task, taskWrapper);
87 | getHandler().postDelayed(taskWrapper, delayMillis);
88 | }
89 |
90 | final static class TaskWrapper implements Runnable {
91 |
92 | Runnable taskImpl;
93 | TaskQueue taskQueue;
94 |
95 | private TaskWrapper(Runnable runnable,TaskQueue queue){
96 | taskImpl = runnable;
97 | this.taskQueue = queue;
98 | }
99 |
100 | public static TaskWrapper create(Runnable runnable,TaskQueue queue){
101 | TaskWrapper taskWrapper = new TaskWrapper(runnable,queue);
102 | return taskWrapper;
103 | }
104 |
105 | @Override
106 | public void run() {
107 |
108 | try {
109 | if(taskImpl!=null){
110 | taskImpl.run();
111 | }
112 | } finally {
113 | taskQueue.remove(this);
114 | }
115 |
116 | }
117 | }
118 |
119 | public int getTaskCount() {
120 | return taskMapping.size();
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/connection/AbstractBluetoothConnection.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.connection;
2 |
3 | import java.io.Closeable;
4 | import java.util.UUID;
5 |
6 | import android.bluetooth.BluetoothDevice;
7 | import android.util.Log;
8 |
9 | import com.devyok.bluetooth.base.BluetoothException;
10 | import com.devyok.bluetooth.connection.BluetoothConnection.State;
11 | import com.devyok.bluetooth.utils.BluetoothUtils;
12 | /**
13 | * @author wei.deng
14 | */
15 | public abstract class AbstractBluetoothConnection implements Connection {
16 |
17 | static final String TAG = AbstractBluetoothConnection.class.getSimpleName();
18 |
19 | protected BluetoothDevice connectedDevice;
20 | protected UUID sppuuid;
21 | protected volatile boolean isCancel;
22 | protected volatile State currentState = State.INIT;
23 | protected TransactCore transactCore;
24 | protected long connectionTimeout = 6*1000;
25 |
26 | public AbstractBluetoothConnection(UUID sppuuid,BluetoothDevice connectedDevice){
27 | this.sppuuid = sppuuid;
28 | this.connectedDevice = connectedDevice;
29 | }
30 |
31 | @Override
32 | public void connect() throws BluetoothConnectionException,
33 | BluetoothConnectionTimeoutException, BluetoothException {
34 | connect(this.sppuuid, this.connectedDevice);
35 | }
36 |
37 | @Override
38 | public UUID getUuid() {
39 | return sppuuid;
40 | }
41 |
42 | @Override
43 | public BluetoothDevice getBluetoothDevice() {
44 | return connectedDevice;
45 | }
46 |
47 | @Override
48 | public long getTimeout() {
49 | return connectionTimeout;
50 | }
51 |
52 | public void setTimeout(long timeout) {
53 | this.connectionTimeout = timeout;
54 | }
55 |
56 | @Override
57 | public void reset() {
58 | isCancel = false;
59 | closeTransactCore();
60 | }
61 |
62 | @Override
63 | public void disconnect() {
64 | closeTransactCore();
65 | }
66 |
67 | @Override
68 | public State getState() {
69 | return this.currentState;
70 | }
71 |
72 | @Override
73 | public TransactCore getCore() {
74 | return this.transactCore;
75 | }
76 |
77 | @Override
78 | public void cancel() {
79 | Log.i(TAG, "[devybt sppconnection] cancel{"+this.getClass().getSimpleName()+"} enter , transactCore = " + transactCore);
80 | isCancel = true;
81 | closeTransactCore();
82 | }
83 |
84 | protected boolean isCancel(){
85 | return isCancel;
86 | }
87 |
88 | protected void closeTransactCore(){
89 | try {
90 | if(this.transactCore instanceof Closeable){
91 | Closeable closeable = (Closeable) this.transactCore;
92 | BluetoothUtils.close(closeable);
93 | }
94 | } finally {
95 | this.transactCore = null;
96 | currentState = State.CLOSED;
97 | }
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/connection/BluetoothConnection.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.connection;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 | import android.os.ParcelUuid;
5 |
6 | import com.devyok.bluetooth.a2dp.A2dpProfileService;
7 | import com.devyok.bluetooth.base.BluetoothException;
8 | import com.devyok.bluetooth.hfp.HFPConnection;
9 | import com.devyok.bluetooth.hfp.HeadsetProfileService;
10 | import com.devyok.bluetooth.utils.BluetoothUtils;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 | import java.util.UUID;
15 | /**
16 | * @author wei.deng
17 | */
18 | public abstract class BluetoothConnection{
19 |
20 | public static final UUID DEFAULT_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
21 |
22 | /**
23 | * 连接状态
24 | * @author wei.deng
25 | */
26 | public enum State {
27 | UNKNOW,
28 | INIT,
29 | CONNECTED,
30 | LISTENING,
31 | CLOSED,
32 | }
33 |
34 | /**
35 | * 连接监听器
36 | * @author wei.deng
37 | */
38 | public static abstract class BluetoothConnectionListener {
39 | public void onConnected(Connection connection) {
40 | }
41 |
42 | public void onDisconnected(Connection connection) {
43 | }
44 | }
45 | /**
46 | * 支持的协议
47 | * @author wei.deng
48 | *
49 | */
50 | public static class Protocol {
51 | private String name;
52 |
53 | public static final Protocol A2DP = new Protocol("a2dp");
54 |
55 | public static final Protocol HFP = new Protocol("hfp");
56 |
57 | public static final Protocol SPP = new Protocol("spp");
58 |
59 | public static final Protocol[] ALL = new Protocol[]{A2DP,HFP,SPP};
60 |
61 | public Protocol(String name){
62 | this.name = name;
63 | }
64 |
65 | public String getName() {
66 | return name;
67 | }
68 |
69 | public static Protocol getProtocol(ParcelUuid uuid){
70 | throw new RuntimeException("stub");
71 | }
72 |
73 | public static Protocol getProtocol(int profile){
74 | if(profile == HeadsetProfileService.PROFILE) {
75 | return Protocol.HFP;
76 | } else if(profile == A2dpProfileService.PROFILE) {
77 | return Protocol.A2DP;
78 | }
79 | return Protocol.SPP;
80 | }
81 |
82 | @Override
83 | public int hashCode() {
84 | return name.hashCode();
85 | }
86 |
87 | @Override
88 | public boolean equals(Object obj) {
89 | Protocol p1 = (Protocol) obj;
90 | return p1.getName().equals(this.name);
91 | }
92 |
93 | }
94 |
95 | /**
96 | * sppconnection builder
97 | * @author wei.deng
98 | */
99 | public static class Builder {
100 | private BluetoothDevice connectedDevice;
101 | private UUID serviceUUID;
102 | private RetryPolicy connectionRetryPolicy;
103 | private BluetoothConnectionListener connectListener;
104 | private long connectionTimeout;
105 | private int companyid = BluetoothUtils.UNKNOW;
106 | final List connectPolicyList = new ArrayList();
107 |
108 | public Builder(){
109 | }
110 |
111 | public Builder setConnectedDevice(BluetoothDevice connectedDevice) {
112 | this.connectedDevice = connectedDevice;
113 | return this;
114 | }
115 |
116 | public Builder setCompanyid(int companyid) {
117 | this.companyid = companyid;
118 | return this;
119 | }
120 |
121 | public Builder setConnectionUUID(UUID sppUUID) {
122 | this.serviceUUID = sppUUID;
123 | return this;
124 | }
125 |
126 | public Builder setConnectionRetryPolicy(RetryPolicy connectionRetryPolicy) {
127 | this.connectionRetryPolicy = connectionRetryPolicy;
128 | return this;
129 | }
130 |
131 | public Builder addDefaultConnectionRetryPolicy(){
132 | this.connectionRetryPolicy = new DefaultRetryPolicy();
133 | return this;
134 | }
135 |
136 | public Builder setConnectionListener(BluetoothConnectionListener lis) {
137 | this.connectListener = lis;
138 | return this;
139 | }
140 |
141 | public Builder addConnectionPolicy(Connection connectPolicy) {
142 | if(!this.connectPolicyList.contains(connectPolicy)) {
143 | this.connectPolicyList.add(connectPolicy);
144 | }
145 | return this;
146 | }
147 |
148 | public Builder setConnectionTimeout(long timeout){
149 | this.connectionTimeout = timeout;
150 | return this;
151 | }
152 |
153 | public Connection build() throws BluetoothException{
154 | if(connectPolicyList.size()>0){
155 | for (Connection connection : connectPolicyList) {
156 | if(connection instanceof AbstractBluetoothConnection>) {
157 | AbstractBluetoothConnection> abstractBluetoothConnection = (AbstractBluetoothConnection>) connection;
158 | abstractBluetoothConnection.connectedDevice = this.connectedDevice;
159 | abstractBluetoothConnection.sppuuid = this.serviceUUID;
160 | abstractBluetoothConnection.setTimeout(connectionTimeout);
161 |
162 | if(abstractBluetoothConnection instanceof HFPConnection){
163 | HFPConnection hfpConnection = (HFPConnection) abstractBluetoothConnection;
164 | hfpConnection.setCompanyid(this.companyid);
165 | }
166 |
167 | }
168 | }
169 | }
170 | return BluetoothConnectionImpl.open(this.serviceUUID, this.connectedDevice, this.connectionRetryPolicy, this.connectListener,this.connectPolicyList.toArray(new Connection[]{}));
171 | }
172 |
173 | }
174 |
175 | }
176 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/connection/BluetoothConnectionException.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.connection;
2 |
3 | import com.devyok.bluetooth.base.BluetoothException;
4 |
5 | /**
6 | * @author wei.deng
7 | */
8 | public class BluetoothConnectionException extends BluetoothException {
9 |
10 | public BluetoothConnectionException(String message) {
11 | super(message);
12 | }
13 |
14 | public BluetoothConnectionException(String message, Throwable cause) {
15 | super(message, cause);
16 | }
17 |
18 | public BluetoothConnectionException(Throwable cause) {
19 | super(cause);
20 | }
21 |
22 | private static final long serialVersionUID = 1L;
23 |
24 | }
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/connection/BluetoothConnectionImpl.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.connection;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 | import android.util.Log;
5 |
6 | import com.devyok.bluetooth.base.BluetoothException;
7 | import com.devyok.bluetooth.connection.BluetoothConnection.BluetoothConnectionListener;
8 | import com.devyok.bluetooth.connection.BluetoothConnection.State;
9 | import com.devyok.bluetooth.utils.BluetoothUtils;
10 |
11 | import java.io.Closeable;
12 | import java.util.ArrayList;
13 | import java.util.List;
14 | import java.util.UUID;
15 | import java.util.concurrent.Callable;
16 | import java.util.concurrent.ExecutionException;
17 | import java.util.concurrent.ExecutorService;
18 | import java.util.concurrent.Executors;
19 | import java.util.concurrent.FutureTask;
20 | import java.util.concurrent.TimeUnit;
21 | import java.util.concurrent.TimeoutException;
22 | /**
23 | * 负责与蓝牙设备建立连接
24 | * @author wei.deng
25 | */
26 | @SuppressWarnings("rawtypes")
27 | final class BluetoothConnectionImpl extends AbstractBluetoothConnection {
28 |
29 | private static final String TAG = BluetoothConnectionImpl.class.getSimpleName();
30 |
31 | final RetryPolicy retryPolicy;
32 | final BluetoothConnectionListener connectionListener;
33 | final List sppConnectPolicyList;
34 | Connection currentConnectPolicy = null;
35 | static final ExecutorService btConnectionExecutorService = Executors.newCachedThreadPool(BluetoothUtils.createThreadFactory("bt.runtime.connection"));
36 |
37 | private BluetoothConnectionImpl(UUID sppuuid,BluetoothDevice connectedDevice){
38 | this(sppuuid,connectedDevice,null,null,null);
39 | }
40 |
41 | private BluetoothConnectionImpl(UUID sppid,BluetoothDevice connectedDevice,Connection extends Closeable>[] connectPolicies,RetryPolicy retryPolicy,BluetoothConnectionListener connectionListener){
42 | super(sppid,connectedDevice);
43 | sppConnectPolicyList = new ArrayList();
44 | if(connectPolicies!=null){
45 | for(int i = 0;i < connectPolicies.length;i++){
46 | sppConnectPolicyList.add(connectPolicies[i]);
47 | }
48 | }
49 | this.retryPolicy = retryPolicy;
50 | this.connectionListener = connectionListener;
51 | }
52 |
53 | static BluetoothConnectionImpl open(BluetoothDevice connectedDevice) throws BluetoothException {
54 | return open(BluetoothConnection.DEFAULT_UUID,connectedDevice,new DefaultRetryPolicy(),null,null);
55 | }
56 |
57 | static BluetoothConnectionImpl open(UUID sppuuid,BluetoothDevice connectedDevice) throws BluetoothException {
58 | return open(sppuuid,connectedDevice,new DefaultRetryPolicy(),null,null);
59 | }
60 |
61 | static BluetoothConnectionImpl open(UUID sppuuid,BluetoothDevice connectedDevice,RetryPolicy policy) throws BluetoothException {
62 | return open(sppuuid,connectedDevice,policy,null,null);
63 | }
64 |
65 | static BluetoothConnectionImpl open(UUID sppuuid,BluetoothDevice connectedDevice,RetryPolicy policy,BluetoothConnectionListener lis) throws BluetoothException {
66 | return open(sppuuid,connectedDevice,policy,lis,null);
67 | }
68 |
69 | /**
70 | * 开启一个SPP连接
71 | * @param sppuuid 连接蓝牙设备时需要的ID
72 | * @param connectedDevice 已连接的蓝牙设备
73 | * @param policy 当SPP连接失败后,尝试重连的策略
74 | * @return
75 | * @throws BluetoothException
76 | */
77 | static BluetoothConnectionImpl open(UUID sppuuid,BluetoothDevice connectedDevice,RetryPolicy policy,BluetoothConnectionListener sppConnectListener,Connection[] sppConnectPolicyArray) throws BluetoothException {
78 |
79 | if(sppuuid == null){
80 | throw new BluetoothException("sppuuid == null");
81 | }
82 |
83 | Log.i(TAG, "[devybt btconnection] open sppuuid = " + sppuuid);
84 |
85 | if(connectedDevice == null){
86 | throw new BluetoothException("connectedDevice == null");
87 | }
88 |
89 | BluetoothConnectionImpl sppConnection = new BluetoothConnectionImpl(sppuuid,connectedDevice,sppConnectPolicyArray,policy,sppConnectListener);
90 | return sppConnection;
91 | }
92 |
93 |
94 | /**
95 | * 连接蓝牙设备
96 | * @throws BluetoothConnectionException
97 | * @throws BluetoothException
98 | */
99 | public void connect() throws BluetoothConnectionException , BluetoothConnectionTimeoutException , BluetoothException{
100 |
101 | try {
102 | Connection connection = currentConnectPolicy;
103 | if(connection!=null){
104 | connection.connect();
105 | } else {
106 | connection = tryConnect();
107 | }
108 |
109 | if(connection!=null && connection.isConnected()){
110 | this.currentConnectPolicy = connection;
111 | try {
112 | resetRetryPolicy();
113 | } finally {
114 | connectedNotifier();
115 | }
116 | }
117 | } catch (BluetoothConnectionException e) {
118 | if(!retry(e)){
119 | throw e;
120 | }
121 | } catch(TimeoutException e){
122 | if(!retry(e)){
123 | throw new BluetoothConnectionTimeoutException("spp connect timeout("+getTotalTimeout()+")" , e);
124 | }
125 | }
126 | catch(Exception e){
127 | throw new BluetoothException(e);
128 | }
129 | }
130 |
131 | boolean retry(Exception e) throws BluetoothConnectionException, BluetoothException{
132 | if(retryPolicy!=null){
133 |
134 | retryPolicy.retry(sppuuid, connectedDevice, e);
135 | return true;
136 | }
137 | return false;
138 | }
139 |
140 | void resetRetryPolicy(){
141 | if(retryPolicy!=null){
142 | retryPolicy.reset();
143 | }
144 | }
145 |
146 | void connectedNotifier(){
147 | if(connectionListener!=null){
148 | connectionListener.onConnected(this);
149 | }
150 | }
151 |
152 | void disconnetedNotifier() {
153 | if(connectionListener!=null){
154 | connectionListener.onDisconnected(this);
155 | }
156 | }
157 |
158 | @Override
159 | public long getTimeout() {
160 | return getTotalTimeout();
161 | }
162 |
163 | @Override
164 | public void cancel() {
165 | super.cancel();
166 | if(currentConnectPolicy!=null){
167 | currentConnectPolicy.cancel();
168 | }
169 | }
170 |
171 | @Override
172 | public void connect(UUID sppuuid, BluetoothDevice connectedDevice) throws BluetoothConnectionException, BluetoothConnectionTimeoutException, BluetoothException {
173 | this.sppuuid = sppuuid;
174 | this.connectedDevice = connectedDevice;
175 | connect();
176 | }
177 |
178 | /**
179 | * 将连接成功的调整到最前面,避免在重连时可以快速连接
180 | * @param bestPolicyIndex
181 | */
182 | void adjustBestConnectPolicy(int bestPolicyIndex){
183 | Log.i(TAG, "[devybt btconnection] adjustBestConnectPolicy bestPolicyIndex = " + bestPolicyIndex);
184 | if(bestPolicyIndex == 0) return ;
185 | Connection bestPolicy = sppConnectPolicyList.remove(bestPolicyIndex);
186 | sppConnectPolicyList.add(0, bestPolicy);
187 | }
188 |
189 | /**
190 | * 尝试获取所有的连接策略,进行循环连接.
191 | * @return
192 | * @throws BluetoothConnectionException
193 | * @throws BluetoothConnectionTimeoutException
194 | * @throws TimeoutException
195 | */
196 | Connection tryConnect() throws BluetoothConnectionException, TimeoutException{
197 |
198 | long totalTimeout = getTotalTimeout();
199 |
200 | Log.i(TAG, "[devybt btconnection] start try connect policy , totalTimeout = " + totalTimeout);
201 | FutureTask> futureTask =
202 | new FutureTask>(new Callable>() {
203 |
204 | @Override
205 | public CallResult call() {
206 |
207 | int size = sppConnectPolicyList.size();
208 | Log.i(TAG, "[devybt btconnection] try connect policy size = " + size);
209 |
210 | BluetoothConnectionException excp = null;
211 | for (int i = 0; i < size; i++) {
212 | final Connection policy = sppConnectPolicyList.get(i);
213 | Log.i(TAG, "[devybt btconnection] try connect policy = " + policy);
214 | policy.reset();
215 | currentConnectPolicy = policy;
216 | try {
217 | policy.connect(sppuuid, connectedDevice);
218 | if(policy.isConnected()) {
219 | adjustBestConnectPolicy(i);
220 | return CallResult.obtain(policy,CallResult.SUCCESS);
221 | }
222 | } catch (BluetoothConnectionException e) {
223 | excp = e;
224 | } catch (BluetoothConnectionTimeoutException e) {
225 | e.printStackTrace();
226 | } catch (BluetoothException e) {
227 | e.printStackTrace();
228 | }
229 | }
230 |
231 | return CallResult.obtain(null, CallResult.EXCEPTION,excp);
232 | }
233 | });
234 |
235 | btConnectionExecutorService.execute(futureTask);
236 |
237 | CallResult callResult = null;
238 | try {
239 | callResult = futureTask.get(totalTimeout,TimeUnit.MILLISECONDS);
240 |
241 | if(callResult.isSuccess()){
242 |
243 | Connection connect = callResult.result;
244 |
245 | Log.i(TAG, "[devybt btconnection] try connect futureTask result = " + connect);
246 |
247 | if(connect!=null && connect.isConnected()) {
248 | return connect;
249 | }
250 | } else {
251 | if(callResult.exception!=null && callResult.exception instanceof BluetoothConnectionException){
252 | throw (BluetoothConnectionException)callResult.exception;
253 | } else {
254 | throw new BluetoothConnectionException(callResult.exception);
255 | }
256 | }
257 | } catch (InterruptedException e) {
258 | e.printStackTrace();
259 | } catch (ExecutionException e) {
260 | e.printStackTrace();
261 | } catch (TimeoutException e) {
262 | //当出现超时之后,有一种情况是socket阻塞在connect上长时间不返回,所以需要调用policy#cancel关闭连接
263 | //关闭之后connect会抛出IOException,这样就打断阻塞了
264 | if(currentConnectPolicy!=null){
265 | currentConnectPolicy.cancel();
266 | }
267 | throw e;
268 | } finally {
269 | currentConnectPolicy = null;
270 | }
271 |
272 | return null;
273 | }
274 |
275 | private long getTotalTimeout() {
276 |
277 | int size = sppConnectPolicyList.size();
278 | long total = 0L;
279 | for (int i = 0; i < size; i++) {
280 | final Connection policy = sppConnectPolicyList.get(i);
281 | total += policy.getTimeout();
282 | }
283 |
284 | return total == 0L ? 6*1000 : total;
285 | }
286 |
287 | @Override
288 | public boolean isConnected() {
289 | return currentConnectPolicy!=null ? currentConnectPolicy.isConnected() : false;
290 | }
291 |
292 | @Override
293 | public State getState() {
294 | return currentConnectPolicy!=null ? currentConnectPolicy.getState() : State.INIT;
295 | }
296 |
297 | @Override
298 | public void disconnect() {
299 | try {
300 | if(currentConnectPolicy!=null){
301 | currentConnectPolicy.disconnect();
302 |
303 | disconnetedNotifier();
304 |
305 | }
306 | } finally {
307 | super.disconnect();
308 | }
309 | }
310 |
311 | static class CallResult {
312 |
313 | public static final int SUCCESS = 0x00;
314 | public static final int EXCEPTION = 0x01;
315 |
316 | Result result;
317 | int status;
318 | Throwable exception;
319 |
320 | public static CallResult obtain(Result result,int status){
321 | return obtain(result,status,null);
322 | }
323 |
324 | public static CallResult obtain(Result result,int status,Throwable exception){
325 | CallResult callResult = new CallResult();
326 | callResult.result = result;
327 | callResult.status = status;
328 | callResult.exception = exception;
329 | return callResult;
330 | }
331 |
332 | public boolean isSuccess(){
333 | return (status == SUCCESS);
334 | }
335 |
336 | }
337 |
338 | }
339 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/connection/BluetoothConnectionStateListener.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.connection;
2 |
3 |
4 | import com.devyok.bluetooth.base.StateInformation;
5 | /**
6 | * @author deng.wei
7 | */
8 | public abstract class BluetoothConnectionStateListener {
9 |
10 | public static final BluetoothConnectionStateListener EMTPY = new BluetoothConnectionStateListener() {
11 | };
12 |
13 | public void onConnecting(StateInformation stateInformation) {
14 | }
15 |
16 | public void onConnected(StateInformation stateInformation) {
17 | }
18 |
19 | public void onDisconnected(StateInformation stateInformation) {
20 | }
21 |
22 | public void onDisconnecting(StateInformation stateInformation) {
23 | }
24 |
25 | public void onError(StateInformation stateInformation) {
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/connection/BluetoothConnectionTimeoutException.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.connection;
2 |
3 | import com.devyok.bluetooth.base.BluetoothException;
4 |
5 |
6 | /**
7 | * @author wei.deng
8 | */
9 | public class BluetoothConnectionTimeoutException extends BluetoothException {
10 |
11 | private static final long serialVersionUID = 1L;
12 | public BluetoothConnectionTimeoutException(String message) {
13 | super(message);
14 | }
15 |
16 | public BluetoothConnectionTimeoutException(String message, Throwable cause) {
17 | super(message, cause);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/connection/BluetoothDeviceConnectionService.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.connection;
2 |
3 | import android.bluetooth.BluetoothAdapter;
4 | import android.util.Log;
5 |
6 | import com.devyok.bluetooth.OkBluetooth;
7 | import com.devyok.bluetooth.base.BaseBluetoothStateChangedListener;
8 | import com.devyok.bluetooth.base.BluetoothException;
9 | import com.devyok.bluetooth.base.BluetoothService;
10 | import com.devyok.bluetooth.base.StateInformation;
11 | import com.devyok.bluetooth.utils.BluetoothUtils;
12 | /**
13 | * @author deng.wei
14 | */
15 | public class BluetoothDeviceConnectionService extends BluetoothService{
16 |
17 | private static String TAG = BluetoothDeviceConnectionService.class.getSimpleName();
18 |
19 | private BluetoothConnectionStateListener mConnectionStateListener = BluetoothConnectionStateListener.EMTPY;
20 | private final BluetoothDeviceConnectionStateListenerImpl stateListenerImpl = new BluetoothDeviceConnectionStateListenerImpl();
21 |
22 | public BluetoothDeviceConnectionService(){
23 | }
24 |
25 | public void setConnectionStateListener(BluetoothConnectionStateListener lis){
26 | this.mConnectionStateListener = lis;
27 | }
28 |
29 | @Override
30 | public boolean init() throws BluetoothException {
31 | // TODO Auto-generated method stub
32 | super.init();
33 | stateListenerImpl.startListener();
34 | return true;
35 |
36 | }
37 |
38 | @Override
39 | public boolean destory() {
40 | super.destory();
41 | stateListenerImpl.stopListener();
42 | mConnectionStateListener = null;
43 | return true;
44 | }
45 |
46 | class BluetoothDeviceConnectionStateListenerImpl extends BaseBluetoothStateChangedListener {
47 |
48 | public BluetoothDeviceConnectionStateListenerImpl(){
49 | }
50 |
51 | @Override
52 | public boolean onChanged(StateInformation stateInformation){
53 |
54 | if(OkBluetooth.isDebugable()){
55 |
56 | int connectionState = OkBluetooth.getConnectionState();
57 | String getConnectionStateString = BluetoothUtils.getConnectionStateString(connectionState);
58 |
59 | Log.i(TAG, "[devybt connect] getConnectionStateString = " + getConnectionStateString);
60 |
61 | BluetoothUtils.dumpBluetoothConnectionInfos(TAG, stateInformation.getIntent());
62 | }
63 |
64 | int currentState = stateInformation.getCurrentState();
65 |
66 | switch (currentState) {
67 | case BluetoothAdapter.STATE_CONNECTING:
68 | mConnectionStateListener.onConnecting(stateInformation);
69 | break;
70 | case BluetoothAdapter.STATE_CONNECTED:
71 | mConnectionStateListener.onConnected(stateInformation);
72 | break;
73 | case BluetoothAdapter.STATE_DISCONNECTING:
74 | mConnectionStateListener.onDisconnecting(stateInformation);
75 | break;
76 | case BluetoothAdapter.STATE_DISCONNECTED:
77 | mConnectionStateListener.onDisconnected(stateInformation);
78 | break;
79 |
80 | default:
81 | break;
82 | }
83 |
84 | return true;
85 | }
86 |
87 | @Override
88 | public String[] actions(){
89 | return new String[]{BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED};
90 | }
91 |
92 | }
93 |
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/connection/Connection.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.connection;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 |
5 | import com.devyok.bluetooth.base.BluetoothException;
6 | import com.devyok.bluetooth.connection.BluetoothConnection.State;
7 |
8 | import java.io.Closeable;
9 | import java.io.IOException;
10 | import java.util.UUID;
11 |
12 | /**
13 | * 蓝牙连接建立的策略
14 | * @author wei.deng
15 | */
16 | public interface Connection {
17 |
18 | public long getTimeout();
19 | public void connect() throws BluetoothConnectionException , BluetoothConnectionTimeoutException , BluetoothException;
20 | public void connect(UUID sppuuid,BluetoothDevice connectedDevice) throws BluetoothConnectionException , BluetoothConnectionTimeoutException , BluetoothException;
21 | public void disconnect();
22 | public boolean isConnected();
23 | public void cancel();
24 | public void reset();
25 | public TransactCore getCore();
26 | public UUID getUuid();
27 | public BluetoothDevice getBluetoothDevice();
28 | public State getState();
29 |
30 | public static Connection> EMPTY = new Connection() {
31 |
32 | @Override
33 | public long getTimeout() {
34 | return -1;
35 | }
36 |
37 | @Override
38 | public void connect() throws BluetoothConnectionException,
39 | BluetoothConnectionTimeoutException, BluetoothException {
40 | throw new BluetoothConnectionException("empty");
41 | }
42 |
43 | @Override
44 | public void connect(UUID sppuuid, BluetoothDevice connectedDevice)
45 | throws BluetoothConnectionException,
46 | BluetoothConnectionTimeoutException, BluetoothException {
47 | throw new BluetoothConnectionException("empty");
48 | }
49 |
50 | @Override
51 | public void disconnect() {
52 | }
53 |
54 | @Override
55 | public boolean isConnected() {
56 | return false;
57 | }
58 |
59 | @Override
60 | public void cancel() {
61 | }
62 |
63 | @Override
64 | public void reset() {
65 | }
66 |
67 | @Override
68 | public Closeable getCore() {
69 | return new Closeable() {
70 |
71 | @Override
72 | public void close() throws IOException {
73 | }
74 | };
75 | }
76 |
77 | @Override
78 | public UUID getUuid() {
79 | return UUID.randomUUID();
80 | }
81 |
82 | @Override
83 | public BluetoothDevice getBluetoothDevice() {
84 | return null;
85 | }
86 |
87 | @Override
88 | public State getState() {
89 | return State.UNKNOW;
90 | }
91 | };
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/connection/DefaultRetryPolicy.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.connection;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 | import android.util.Log;
5 |
6 | import com.devyok.bluetooth.base.BluetoothException;
7 |
8 | import java.util.UUID;
9 |
10 |
11 | /**
12 | * 默认的重连实现
13 | * @author wei.deng
14 | *
15 | */
16 | public final class DefaultRetryPolicy implements RetryPolicy{
17 |
18 | static final String TAG = DefaultRetryPolicy.class.getSimpleName();
19 |
20 | static final int DEFAULT_RETRY_COUNT = 3;
21 |
22 | private int maxRetryCount = DEFAULT_RETRY_COUNT;
23 |
24 | private int currentRetryCount = 0;
25 |
26 | static int[] TIMEOUT = new int[]{100,500,1000};
27 |
28 | public DefaultRetryPolicy(){
29 | this(DEFAULT_RETRY_COUNT);
30 | }
31 |
32 | public DefaultRetryPolicy(int maxCount){
33 | maxRetryCount = maxCount;
34 | }
35 |
36 | @Override
37 | public int getCurrentRetryCount() {
38 | return currentRetryCount;
39 | }
40 |
41 | @Override
42 | public void retry(UUID sppuuid,BluetoothDevice connectedDevice,Exception error) throws BluetoothConnectionException,BluetoothException {
43 |
44 | if(currentRetryCount>=maxRetryCount){
45 | throw new BluetoothConnectionException("spp retry connect fail",error);
46 | }
47 |
48 | try {
49 | Thread.sleep(TIMEOUT[getCurrentRetryCount()]);
50 | } catch (InterruptedException e1) {
51 | e1.printStackTrace();
52 | }
53 |
54 | currentRetryCount++;
55 | Log.i(TAG, "[devybt sppconnection] retryconnect count = " + currentRetryCount);
56 |
57 | BluetoothConnectionImpl sppConnection = BluetoothConnectionImpl.open(sppuuid,connectedDevice,null);
58 | try {
59 | sppConnection.connect();
60 | } catch (BluetoothConnectionException e) {
61 | Log.i(TAG, "[devybt sppconnection] retryconnect BluetoothConnectionException");
62 |
63 | retry(sppuuid, connectedDevice, error);
64 |
65 | } catch(BluetoothConnectionTimeoutException e){
66 | Log.i(TAG, "[devybt sppconnection] retryconnect BluetoothConnectionTimeoutException");
67 |
68 | retry(sppuuid, connectedDevice, error);
69 |
70 | } catch (BluetoothException e) {
71 | throw e;
72 | }
73 |
74 | }
75 |
76 | @Override
77 | public void reset() {
78 | currentRetryCount = 0;
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/connection/RetryPolicy.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.connection;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 |
5 | import com.devyok.bluetooth.base.BluetoothException;
6 |
7 | import java.util.UUID;
8 |
9 |
10 | /**
11 | * 重连策略
12 | * 默认实现:{@link DefaultRetryPolicy}
13 | * @author wei.deng
14 | */
15 | public interface RetryPolicy {
16 | public void reset();
17 | public int getCurrentRetryCount();
18 | public void retry(UUID sppuuid,BluetoothDevice connectedDevice,Exception e) throws BluetoothConnectionException,BluetoothException;
19 | }
20 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/debug/DebugHelper.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.debug;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | import com.devyok.bluetooth.OkBluetooth;
8 | import com.devyok.bluetooth.utils.BluetoothUtils;
9 |
10 | /**
11 | * 仅运行在adb环境下
12 | *
13 | * 输出系统信息:adb shell am broadcast -a com.devyok.DEBUG_SYSTEM_BLUETOOTH_INFO
14 | * 弹出控制界面:adb shell am broadcast -a com.devyok.DEBUG_UI_CONSOLE
15 | * 输出LOG :adb logcat -v time debugBluetooth:I *:S
16 | * 系统社设置 :adb shell am start com.android.settings/com.android.settings.Settings
17 | * @author wei.deng
18 | */
19 | public class DebugHelper extends BroadcastReceiver {
20 |
21 | public static final String ACTION_DEBUG_SYSTEM_INFO = "com.devyok.DEBUG_SYSTEM_BLUETOOTH_INFO";
22 |
23 | public static final String ACTION_DEBUG_ACTIVITY = "com.devyok.DEBUG_UI_CONSOLE";
24 |
25 | public static final String TAG = "debugBluetooth";
26 |
27 | @Override
28 | public void onReceive(Context context, Intent intent) {
29 |
30 | if(intent == null) return ;
31 |
32 | if(!OkBluetooth.isReady()) {
33 | OkBluetooth.init(context);
34 | }
35 |
36 |
37 | String action = intent.getAction();
38 |
39 | if(ACTION_DEBUG_SYSTEM_INFO.equals(action)) {
40 |
41 | BluetoothUtils.dumpBluetoothAllSystemInfos(TAG);
42 |
43 | } else if(ACTION_DEBUG_ACTIVITY.equals(action)){
44 |
45 | Intent impl = new Intent(OkBluetooth.getContext(),DebugUIConsoleActivity.class);
46 | impl.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
47 | OkBluetooth.getContext().startActivity(impl);
48 |
49 | }
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/hfp/BluetoothHeadsetProfileService.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.hfp;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 |
5 | import com.devyok.bluetooth.base.BluetoothProfileService;
6 | /**
7 | * @author wei.deng
8 | */
9 | public interface BluetoothHeadsetProfileService extends BluetoothProfileService {
10 |
11 | public interface BluetoothHeadsetAudioStateListener {
12 | public void onAudioConnected(BluetoothDevice bluetoothDevice, BluetoothHeadsetProfileService service);
13 | public void onAudioDisconnected(BluetoothDevice bluetoothDevice, BluetoothHeadsetProfileService service);
14 | public void onAudioConnecting(BluetoothDevice bluetoothDevice, BluetoothHeadsetProfileService service);
15 | }
16 |
17 | public void registerAudioStateChangedListener(BluetoothHeadsetAudioStateListener lis);
18 | public void unregisterAudioStateChangedListener(BluetoothHeadsetAudioStateListener lis);
19 |
20 | public boolean isAudioConnected(final BluetoothDevice device);
21 |
22 | public boolean disconnectAudio();
23 |
24 | public boolean connectAudio();
25 |
26 | public int getAudioState(final BluetoothDevice device);
27 |
28 | public boolean isAudioOn();
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/hfp/HFPConnection.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.hfp;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 |
5 | import com.devyok.bluetooth.base.BluetoothException;
6 | import com.devyok.bluetooth.connection.AbstractBluetoothConnection;
7 | import com.devyok.bluetooth.connection.BluetoothConnection.State;
8 | import com.devyok.bluetooth.connection.BluetoothConnectionException;
9 | import com.devyok.bluetooth.connection.BluetoothConnectionTimeoutException;
10 | import com.devyok.bluetooth.utils.BluetoothUtils;
11 |
12 | import java.util.UUID;
13 | /**
14 | * @author wei.deng
15 | */
16 | public final class HFPConnection extends AbstractBluetoothConnection{
17 |
18 | private int companyid;
19 | volatile boolean isConnected = false;
20 |
21 | public HFPConnection(){
22 | this(BluetoothUtils.UNKNOW);
23 | }
24 |
25 | public HFPConnection(int companyid) {
26 | this(null,null,companyid);
27 | }
28 |
29 | public boolean checkCompanyId(){
30 | if(companyid == BluetoothUtils.UNKNOW){
31 | return false;
32 | }
33 | return true;
34 | }
35 |
36 | public void setCompanyid(int companyid) {
37 | this.companyid = companyid;
38 | }
39 |
40 | public HFPConnection(UUID sppuuid, BluetoothDevice connectedDevice) {
41 | this(sppuuid,connectedDevice,-1);
42 | }
43 |
44 | public HFPConnection(UUID sppuuid, BluetoothDevice connectedDevice,int companyid) {
45 | super(sppuuid, connectedDevice);
46 | this.companyid = companyid;
47 | }
48 |
49 | @Override
50 | public void connect(UUID sppuuid, BluetoothDevice connectedDevice) throws BluetoothConnectionException,
51 | BluetoothConnectionTimeoutException, BluetoothException {
52 | try {
53 | HFPConnectionImpl impl = HFPConnectionImpl.connect(companyid);
54 | this.transactCore = impl;
55 | isConnected = true;
56 | this.currentState = State.CONNECTED;
57 | } catch(Exception e){
58 | isConnected = false;
59 | throw e;
60 | }
61 | }
62 |
63 | @Override
64 | public void disconnect() {
65 | try {
66 | super.disconnect();
67 | } finally {
68 | isConnected = false;
69 | }
70 | }
71 |
72 | @Override
73 | public boolean isConnected() {
74 | return isConnected;
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/hfp/HFPConnectionImpl.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.hfp;
2 |
3 | import java.io.Closeable;
4 | import java.io.IOException;
5 |
6 | import android.bluetooth.BluetoothDevice;
7 | import android.bluetooth.BluetoothHeadset;
8 | import android.content.BroadcastReceiver;
9 | import android.content.Context;
10 | import android.content.Intent;
11 | import android.content.IntentFilter;
12 | import android.os.Parcelable;
13 | import android.util.Log;
14 |
15 | import com.devyok.bluetooth.OkBluetooth;
16 | import com.devyok.bluetooth.base.BluetoothException;
17 | import com.devyok.bluetooth.connection.BluetoothConnection.Protocol;
18 | import com.devyok.bluetooth.message.BluetoothMessage;
19 | import com.devyok.bluetooth.message.BluetoothMessageDispatcher;
20 | import com.devyok.bluetooth.utils.BluetoothUtils;
21 | /**
22 | * @author wei.deng
23 | */
24 | class HFPConnectionImpl extends BroadcastReceiver implements Closeable{
25 |
26 | static String TAG = HFPConnectionImpl.class.getSimpleName();
27 |
28 | private HFPConnectionImpl(){
29 | }
30 |
31 | public static HFPConnectionImpl connect(int companyid) throws BluetoothException {
32 |
33 | try {
34 | HFPConnectionImpl connectionImpl = new HFPConnectionImpl();
35 |
36 | IntentFilter intentFilter = new IntentFilter(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
37 |
38 | if(companyid<0){
39 | intentFilter.addCategory("android.bluetooth.headset.intent.category.companyid");
40 | } else {
41 | intentFilter.addCategory("android.bluetooth.headset.intent.category.companyid"+"." + companyid);
42 | }
43 |
44 | OkBluetooth.getContext().registerReceiver(connectionImpl, intentFilter);
45 |
46 | return connectionImpl;
47 | } catch(Exception e){
48 | throw new BluetoothException("connect fail", e);
49 | }
50 | }
51 |
52 | @Override
53 | public void close() throws IOException {
54 | try {
55 | OkBluetooth.getContext().unregisterReceiver(this);
56 | } catch(Exception e){
57 | throw new IOException("unregisterReceiver fail",e);
58 | }
59 | }
60 |
61 | @Override
62 | public void onReceive(Context context, Intent intent) {
63 |
64 | if(intent == null){
65 | return ;
66 | }
67 |
68 | String cmd = intent.getStringExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD);
69 | Object[] cmdArgs = (Object[]) intent.getExtras().get(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS);
70 | int cmdType = intent.getIntExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE, -1);
71 | Parcelable device = (Parcelable)intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
72 | String cmdTypeString = BluetoothUtils.getHeadsetEventTypeString(cmdType);
73 |
74 | String cmdArgsString = BluetoothUtils.toString(cmdArgs);
75 |
76 | BluetoothMessage bluetoothMessage = BluetoothMessage.obtain(cmdArgsString,Protocol.HFP);
77 |
78 | if(device!=null){
79 | bluetoothMessage.setBluetoothDevice((BluetoothDevice) device);
80 | }
81 |
82 | BluetoothMessageDispatcher.dispatch(bluetoothMessage);
83 |
84 | Log.i(TAG, "[devybt sppconnection] cmd = " + cmd + ", args = " + cmdArgsString + " , cmdTypeString = " + cmdTypeString);
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/hfp/HeadsetProfileService.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.hfp;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 | import android.bluetooth.BluetoothHeadset;
5 | import android.bluetooth.BluetoothProfile;
6 | import android.bluetooth.BluetoothUuid;
7 | import android.content.BroadcastReceiver;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.content.IntentFilter;
11 | import android.os.ParcelUuid;
12 | import android.util.Log;
13 |
14 | import com.devyok.bluetooth.OkBluetooth;
15 | import com.devyok.bluetooth.base.BluetoothProfileService;
16 | import com.devyok.bluetooth.base.BluetoothProfileServiceTemplate;
17 | import com.devyok.bluetooth.base.BluetoothRuntimeException;
18 | import com.devyok.bluetooth.utils.BluetoothUtils;
19 |
20 | /**
21 | * @author wei.deng
22 | */
23 | public class HeadsetProfileService extends BluetoothProfileServiceTemplate implements BluetoothHeadsetProfileService{
24 |
25 | public static final ParcelUuid[] UUIDS = {
26 | BluetoothUuid.HSP,
27 | BluetoothUuid.Handsfree,
28 | };
29 |
30 | public static final int PROFILE = BluetoothProfile.HEADSET;
31 |
32 | private BluetoothHeadsetProfileService.BluetoothHeadsetAudioStateListener audioStateListener;
33 | private BroadcastReceiver audioStateReceiverImpl;
34 |
35 | public HeadsetProfileService() {
36 | super(PROFILE);
37 | }
38 |
39 | public HeadsetProfileService(BluetoothProfileService decorater) {
40 | super(PROFILE,decorater);
41 | }
42 |
43 | public HeadsetProfileService(int profileType) {
44 | super(profileType);
45 | throw new BluetoothRuntimeException("not support");
46 | }
47 |
48 | /**
49 | * 如果sco已经连接上,则callback返回true
50 | * @param device
51 | */
52 | @Override
53 | public boolean isAudioConnected(final BluetoothDevice device) {
54 |
55 | if(realService == null) return false;
56 |
57 | return ((BluetoothHeadset) realService).isAudioConnected(device);
58 |
59 | }
60 |
61 | @Override
62 | public boolean disconnectAudio() {
63 | if(realService == null) return false;
64 |
65 | return ((BluetoothHeadset) realService).disconnectAudio();
66 | }
67 |
68 | @Override
69 | public boolean connectAudio() {
70 |
71 | if(realService == null) return false;
72 |
73 | return ((BluetoothHeadset) realService).connectAudio();
74 |
75 | }
76 |
77 | @Override
78 | public boolean isAudioOn(){
79 | if(realService == null) return false;
80 | return ((BluetoothHeadset) realService).isAudioOn();
81 | }
82 |
83 | @Override
84 | public int getAudioState(final BluetoothDevice device){
85 | if(realService == null) return BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
86 | return ((BluetoothHeadset) realService).getAudioState(device);
87 | }
88 |
89 | @Override
90 | protected void onRealServiceConnected() {
91 | super.onRealServiceConnected();
92 |
93 | if(audioStateReceiverImpl == null){
94 | OkBluetooth.getContext().registerReceiver(audioStateReceiverImpl = new BroadcastReceiver() {
95 |
96 | @Override
97 | public void onReceive(Context context, Intent intent) {
98 |
99 | int newState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, -1);
100 | int previousState = intent.getIntExtra(BluetoothHeadset.EXTRA_PREVIOUS_STATE, -1);
101 |
102 | Log.i(TAG, "[devybt connect] hfp audio new state = " + BluetoothUtils.getScoStateStringFromHeadsetProfile(newState) + " , pre state = " + BluetoothUtils.getScoStateStringFromHeadsetProfile(previousState));
103 |
104 | BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
105 |
106 | BluetoothUtils.dumpBluetoothDevice(TAG, device);
107 |
108 | if(audioStateListener!=null){
109 |
110 | if(newState == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
111 | audioStateListener.onAudioConnected(device,HeadsetProfileService.this);
112 | } else if(newState == BluetoothHeadset.STATE_AUDIO_DISCONNECTED){
113 | audioStateListener.onAudioDisconnected(device, HeadsetProfileService.this);
114 | } else if(newState == BluetoothHeadset.STATE_AUDIO_CONNECTING) {
115 | audioStateListener.onAudioConnecting(device, HeadsetProfileService.this);
116 | }
117 |
118 | }
119 |
120 | }
121 | }, new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED));
122 | }
123 | }
124 |
125 | @Override
126 | protected void onRealServiceDisconnected() {
127 | super.onRealServiceDisconnected();
128 | if(audioStateReceiverImpl!=null){
129 | OkBluetooth.getContext().unregisterReceiver(audioStateReceiverImpl);
130 | audioStateReceiverImpl = null;
131 | }
132 | }
133 |
134 | @Override
135 | protected ConnectionStateListenerArgs make() {
136 | return new ConnectionStateListenerArgs() {
137 |
138 | @Override
139 | public String extraPreState() {
140 | return BluetoothHeadset.EXTRA_PREVIOUS_STATE;
141 | }
142 |
143 | @Override
144 | public String extraNewState() {
145 | return BluetoothHeadset.EXTRA_STATE;
146 | }
147 |
148 | @Override
149 | public String extraDevice() {
150 | return BluetoothDevice.EXTRA_DEVICE;
151 | }
152 |
153 | @Override
154 | public String action() {
155 | return BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED;
156 | }
157 | };
158 | }
159 |
160 | @Override
161 | public void registerAudioStateChangedListener(
162 | BluetoothHeadsetAudioStateListener lis) {
163 | audioStateListener = lis;
164 | }
165 |
166 | @Override
167 | public void unregisterAudioStateChangedListener(
168 | BluetoothHeadsetAudioStateListener lis) {
169 | audioStateListener = null;
170 | }
171 |
172 | }
173 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/message/BluetoothMessage.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.message;
2 |
3 | import java.util.UUID;
4 |
5 | import com.devyok.bluetooth.connection.BluetoothConnection.Protocol;
6 |
7 | import android.bluetooth.BluetoothDevice;
8 |
9 | /**
10 | * @author wei.deng
11 | */
12 | public class BluetoothMessage {
13 | private String id;
14 |
15 | private long time;
16 | private DataType dataBody;
17 | private Protocol protocol;
18 | private BluetoothDevice bluetoothDevice;
19 |
20 | public BluetoothMessage(){
21 | this.id = UUID.randomUUID().toString();
22 | }
23 |
24 | public static BluetoothMessage obtain(DataType data,Protocol protocol){
25 | return obtain(System.currentTimeMillis(), data,protocol);
26 | }
27 |
28 | public static BluetoothMessage obtain(long time,DataType data,Protocol protocol){
29 | BluetoothMessage message = new BluetoothMessage();
30 | message.time = time;
31 | message.dataBody = data;
32 | message.protocol = protocol;
33 | return message;
34 | }
35 |
36 | public BluetoothDevice getBluetoothDevice() {
37 | return bluetoothDevice;
38 | }
39 |
40 | public void setBluetoothDevice(BluetoothDevice bluetoothDevice) {
41 | this.bluetoothDevice = bluetoothDevice;
42 | }
43 |
44 | public long getTime(){
45 | return time;
46 | }
47 |
48 | public DataType getBodyData(){
49 | return dataBody;
50 | }
51 |
52 | public Protocol getProtocol(){
53 | return protocol;
54 | }
55 |
56 | @Override
57 | public int hashCode() {
58 | return this.id.hashCode();
59 | }
60 |
61 | @Override
62 | public boolean equals(Object obj) {
63 |
64 | BluetoothMessage msg = (BluetoothMessage) obj;
65 |
66 | if(this.id.equals(msg.id)){
67 | return true;
68 | }
69 |
70 | return false;
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/message/BluetoothMessageDispatcher.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.message;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.List;
6 | import java.util.concurrent.ConcurrentHashMap;
7 | import java.util.concurrent.ExecutorService;
8 | import java.util.concurrent.Executors;
9 |
10 | import com.devyok.bluetooth.OkBluetooth;
11 | import com.devyok.bluetooth.connection.BluetoothConnection.Protocol;
12 | import com.devyok.bluetooth.utils.BluetoothUtils;
13 | /**
14 | * @author wei.deng
15 | */
16 | public final class BluetoothMessageDispatcher implements BluetoothMessageHandler{
17 |
18 | final ConcurrentHashMap>> receivers = new ConcurrentHashMap>>();
19 |
20 | static ExecutorService dispatcherThreadPool = Executors.newSingleThreadExecutor(BluetoothUtils.createThreadFactory("bt.runtime.message-dispatcher"));
21 |
22 | static BluetoothMessageHandler> instance;
23 |
24 | public static BluetoothMessageHandler getDispatcher(){
25 | if(instance == null){
26 | instance = new BluetoothMessageDispatcher();
27 | }
28 | return (BluetoothMessageHandler) instance;
29 | }
30 |
31 | public void registerBluetoothMessageReceiver(Protocol protocol,BluetoothMessageReceiver receiver) {
32 |
33 | List> list = receivers.get(protocol);
34 |
35 | if(list == null){
36 | list = Collections.synchronizedList(new ArrayList>());
37 | }
38 |
39 | if(!list.contains(receiver)){
40 | list.add(receiver);
41 | }
42 |
43 | receivers.put(protocol, list);
44 | }
45 |
46 | public void unregisterBluetoothMessageReceiver(Protocol protocol,BluetoothMessageReceiver receiver) {
47 | List> list = receivers.get(protocol);
48 | list.remove(receiver);
49 | }
50 |
51 | public void clear(Protocol protocol) {
52 | receivers.remove(protocol);
53 | }
54 |
55 | public void clearAll() {
56 | receivers.clear();
57 | }
58 |
59 | class HandleTask implements Runnable {
60 |
61 | BluetoothMessage message;
62 |
63 | public HandleTask(BluetoothMessage message){
64 | this.message = message;
65 | }
66 |
67 | @Override
68 | public void run() {
69 |
70 | List> list = receivers.get(message.getProtocol());
71 |
72 | if(list!=null){
73 | int size = list.size();
74 |
75 | for(int i = 0;i < size;i++){
76 | BluetoothMessageReceiver receive = list.get(i);
77 | if(receive!=null){
78 | receive.onReceive(message);
79 | }
80 | }
81 | }
82 |
83 | }
84 | }
85 |
86 | public void handle(BluetoothMessage message) {
87 | dispatcherThreadPool.submit(new HandleTask(message));
88 | }
89 |
90 | public static void dispatch(BluetoothMessage message){
91 | BluetoothMessageHandler dispatcher = OkBluetooth.getConfiguration().getDispatcher();
92 | dispatcher.handle(message);
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/message/BluetoothMessageHandler.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.message;
2 | /**
3 | * @author wei.deng
4 | */
5 | public interface BluetoothMessageHandler {
6 |
7 | public void handle(BluetoothMessage bluetoothMessage);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/message/BluetoothMessageReceiver.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.message;
2 | /**
3 | * @author wei.deng
4 | */
5 | public abstract class BluetoothMessageReceiver {
6 |
7 | public abstract boolean onReceive(BluetoothMessage message);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/sco/BluetoothSCOService.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.sco;
2 |
3 | import android.content.Context;
4 | import android.media.AudioManager;
5 | import android.util.Log;
6 |
7 | import com.devyok.bluetooth.OkBluetooth;
8 | import com.devyok.bluetooth.base.BaseBluetoothStateChangedListener;
9 | import com.devyok.bluetooth.base.BluetoothException;
10 | import com.devyok.bluetooth.base.BluetoothService;
11 | import com.devyok.bluetooth.base.StateInformation;
12 | import com.devyok.bluetooth.connection.BluetoothConnectionStateListener;
13 | import com.devyok.bluetooth.utils.BluetoothUtils;
14 | /**
15 | * @author deng.wei
16 | */
17 | public class BluetoothSCOService extends BluetoothService{
18 |
19 | private static final String TAG = BluetoothSCOService.class.getSimpleName();
20 |
21 | private BluetoothConnectionStateListener mScoStateListener = BluetoothConnectionStateListener.EMTPY;
22 | private final ScoStateListenerImpl stateListenerImpl = new ScoStateListenerImpl();
23 |
24 | public BluetoothSCOService(){
25 | }
26 |
27 | @Override
28 | public boolean init() throws BluetoothException {
29 | super.init();
30 | stateListenerImpl.startListener();
31 | return true;
32 | }
33 |
34 | @Override
35 | public boolean destory() {
36 | super.destory();
37 | stateListenerImpl.stopListener();
38 | mScoStateListener = null;
39 | return true;
40 | }
41 |
42 | public void setConnectionStateListener(BluetoothConnectionStateListener lis){
43 | this.mScoStateListener = (lis!=null ? lis : BluetoothConnectionStateListener.EMTPY);
44 | }
45 |
46 | public boolean isConnectedSco(){
47 | AudioManager am = getAudioManager();
48 |
49 | boolean isBluetoothScoOn = am.isBluetoothScoOn();
50 | boolean isSpeakphoneOn = am.isSpeakerphoneOn();
51 | int audioMode = am.getMode();
52 |
53 | if(OkBluetooth.isBluetoothEnable() && isBluetoothScoOn && !isSpeakphoneOn && AudioManager.MODE_IN_COMMUNICATION == audioMode) {
54 | return true;
55 | }
56 |
57 | return false;
58 | }
59 |
60 | public void startSco(){
61 | AudioManager am = getAudioManager();
62 | boolean isBluetoothScoOn = am.isBluetoothScoOn();
63 |
64 | Log.i(TAG, "[devybt sco] startTryConnectSco startSco enter , isBluetoothScoOn = " + isBluetoothScoOn);
65 | if(!am.isBluetoothScoOn()) {
66 | am.setBluetoothScoOn(true);
67 | am.startBluetoothSco();
68 | }
69 | Log.i(TAG, "[devybt sco] startTryConnectSco startSco exit");
70 | }
71 |
72 | public void stopSco(){
73 | AudioManager am = getAudioManager();
74 | am.stopBluetoothSco();
75 | am.setBluetoothScoOn(false);
76 | }
77 |
78 | AudioManager getAudioManager(){
79 | return (AudioManager) OkBluetooth.getContext().getSystemService(Context.AUDIO_SERVICE);
80 | }
81 |
82 |
83 | private class ScoStateListenerImpl extends BaseBluetoothStateChangedListener {
84 |
85 | public ScoStateListenerImpl(){
86 | }
87 |
88 | @Override
89 | public boolean onChanged(StateInformation information) {
90 |
91 | if(OkBluetooth.isDebugable()){
92 | BluetoothUtils.dumpBluetoothScoStateInfos(TAG, information.getIntent());
93 | }
94 |
95 | int currentState = information.getCurrentState();
96 |
97 | switch (currentState) {
98 | case AudioManager.SCO_AUDIO_STATE_CONNECTING:
99 | mScoStateListener.onConnecting(information);
100 | break;
101 | case AudioManager.SCO_AUDIO_STATE_CONNECTED:
102 | mScoStateListener.onConnected(information);
103 | break;
104 | case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
105 | mScoStateListener.onDisconnected(information);
106 | break;
107 | case AudioManager.SCO_AUDIO_STATE_ERROR:
108 | mScoStateListener.onError(information);
109 | break;
110 | default:
111 | break;
112 | }
113 |
114 | return true;
115 | }
116 |
117 |
118 | @Override
119 | public String[] actions() {
120 | return new String[]{AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED};
121 | }
122 |
123 |
124 | }
125 |
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/spp/AbstractSPPConnection.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.spp;
2 |
3 | import java.util.UUID;
4 |
5 | import android.bluetooth.BluetoothDevice;
6 | import android.bluetooth.BluetoothSocket;
7 |
8 | import com.devyok.bluetooth.OkBluetooth;
9 | import com.devyok.bluetooth.connection.AbstractBluetoothConnection;
10 | import com.devyok.bluetooth.connection.BluetoothConnection.State;
11 | import com.devyok.bluetooth.utils.BluetoothUtils;
12 | /**
13 | * @author wei.deng
14 | */
15 | public abstract class AbstractSPPConnection extends AbstractBluetoothConnection {
16 |
17 | static final String TAG = AbstractSPPConnection.class.getSimpleName();
18 |
19 | protected SPPMessageReceiver messageReceiver;
20 |
21 | public AbstractSPPConnection(UUID sppuuid,BluetoothDevice connectedDevice){
22 | super(sppuuid,connectedDevice);
23 | }
24 |
25 | @Override
26 | public boolean isConnected(){
27 | return transactCore!=null ? transactCore.isConnected() : false;
28 | }
29 |
30 | @Override
31 | public State getState(){
32 | return BluetoothUtils.getBluetoothSocketState(this.transactCore);
33 | }
34 |
35 | public void onConnected(){
36 |
37 | if(messageReceiver!=null){
38 | messageReceiver.stopReceiver();
39 | }
40 |
41 | SPPBluetoothMessageParser parser = OkBluetooth.getSppMessageParser();
42 | messageReceiver = new SPPMessageReceiver(this.transactCore,parser == null ? new DefaultSPPMessageParser() : parser,this.getBluetoothDevice());
43 | messageReceiver.start();
44 | }
45 |
46 | @Override
47 | protected void closeTransactCore() {
48 | super.closeTransactCore();
49 |
50 | if(messageReceiver!=null){
51 | messageReceiver.closeStream();
52 | messageReceiver = null;
53 | }
54 |
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/spp/DefaultSPPMessageParser.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.spp;
2 |
3 | import com.devyok.bluetooth.connection.BluetoothConnection.Protocol;
4 | import com.devyok.bluetooth.message.BluetoothMessage;
5 |
6 | import android.bluetooth.BluetoothDevice;
7 | /**
8 | * @author wei.deng
9 | */
10 | public class DefaultSPPMessageParser implements SPPBluetoothMessageParser {
11 |
12 | final StringBuilder readMessage = new StringBuilder();
13 |
14 | @Override
15 | public BluetoothMessage[] parse(byte[] buffer, int readCount,Protocol protocol,BluetoothDevice device) {
16 | String readed = new String(buffer, 0, readCount);
17 | readMessage.append(readed);
18 | if (readed.contains("\n")) {
19 | BluetoothMessage message = BluetoothMessage.obtain(new String(readMessage.toString()), protocol);
20 | readMessage.setLength(0);
21 | return new BluetoothMessage[]{message};
22 | }
23 | return null;
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/spp/SPPBluetoothMessageParser.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.spp;
2 |
3 | import com.devyok.bluetooth.connection.BluetoothConnection.Protocol;
4 | import com.devyok.bluetooth.message.BluetoothMessage;
5 |
6 | import android.bluetooth.BluetoothDevice;
7 | /**
8 | * @author wei.deng
9 | */
10 | public interface SPPBluetoothMessageParser {
11 |
12 | public static final SPPBluetoothMessageParser DEFAULT = new SPPBluetoothMessageParser() {
13 |
14 | final StringBuilder readMessage = new StringBuilder();
15 |
16 | @Override
17 | public BluetoothMessage[] parse(byte[] buffer, int readCount,Protocol protocol,BluetoothDevice device) {
18 | String readed = new String(buffer, 0, readCount);
19 | readMessage.append(readed);
20 | if (readed.contains("\n")) {
21 | BluetoothMessage message = BluetoothMessage.obtain(new String(readMessage.toString()), protocol);
22 | readMessage.setLength(0);
23 | return new BluetoothMessage[]{message};
24 | }
25 | return null;
26 | }
27 |
28 | };
29 |
30 | public BluetoothMessage[] parse(byte[] buffer, int readCount, Protocol protocol, BluetoothDevice device);
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/spp/SPPConnectionInsecurePolicy.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.spp;
2 |
3 | import android.bluetooth.BluetoothDevice;
4 | import android.bluetooth.BluetoothSocket;
5 | import android.os.Build;
6 | import android.util.Log;
7 |
8 | import com.devyok.bluetooth.connection.BluetoothConnectionException;
9 |
10 | import java.io.IOException;
11 | import java.lang.reflect.Method;
12 | import java.util.UUID;
13 | /**
14 | * @author wei.deng
15 | */
16 | public class SPPConnectionInsecurePolicy extends AbstractSPPConnection {
17 |
18 | public SPPConnectionInsecurePolicy(){
19 | this(null,null);
20 | }
21 |
22 | public SPPConnectionInsecurePolicy(UUID sppuuid,
23 | BluetoothDevice connectedDevice) {
24 | super(sppuuid, connectedDevice);
25 | }
26 |
27 | static final String TAG = SPPConnectionInsecurePolicy.class.getSimpleName();
28 |
29 | @Override
30 | public void connect(UUID sppuuid,BluetoothDevice connectedDevice) throws BluetoothConnectionException{
31 |
32 | Log.i(TAG, "[devybt sppconnection] SPPConnectionDefaultPolicy start try connect , isCancel("+isCancel()+") , sppuuid = " + sppuuid);
33 |
34 | if (Build.VERSION.SDK_INT >= 10) { //不安全
35 | Class> cls = BluetoothDevice.class;
36 | try {
37 | Method m = cls.getMethod("createInsecureRfcommSocketToServiceRecord",new Class[] { UUID.class });
38 | transactCore = (BluetoothSocket) m.invoke(connectedDevice,new Object[] { sppuuid });
39 | } catch (Exception e) {
40 | Log.i(TAG, "[devybt sppconnection] createInsecureRfcommSocketToServiceRecord Exception");
41 | throw new BluetoothConnectionException("createInsecureRfcommSocketToServiceRecord exception",e);
42 | }
43 | } else {
44 | throw new BluetoothConnectionException("sdk not support insecure connection");
45 | }
46 |
47 | try {
48 | if(!isCancel() && transactCore != null){
49 | transactCore.connect();
50 | }
51 | } catch (IOException e) {
52 | closeTransactCore();
53 | Log.i(TAG, "[devybt sppconnection] try connect IOException");
54 | throw new BluetoothConnectionException("spp connect exception" , e);
55 | }
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/spp/SPPConnectionSecurePolicy.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.spp;
2 |
3 | import java.io.IOException;
4 | import java.util.UUID;
5 |
6 | import android.bluetooth.BluetoothDevice;
7 | import android.util.Log;
8 |
9 | import com.devyok.bluetooth.connection.BluetoothConnectionException;
10 | /**
11 | * @author wei.deng
12 | */
13 | public class SPPConnectionSecurePolicy extends AbstractSPPConnection {
14 |
15 | static int exeCount = 0;
16 |
17 | public SPPConnectionSecurePolicy(){
18 | this(null,null);
19 | }
20 |
21 | public SPPConnectionSecurePolicy(UUID sppuuid, BluetoothDevice connectedDevice) {
22 | super(sppuuid, connectedDevice);
23 | }
24 |
25 | static final String TAG = SPPConnectionSecurePolicy.class.getSimpleName();
26 |
27 | @Override
28 | public void connect(UUID sppuuid,BluetoothDevice connectedDevice) throws BluetoothConnectionException{
29 |
30 | Log.i(TAG, "[devybt sppconnection] SPPConnectionSecurePolicy start try connect , isCancel("+isCancel()+") , sppuuid = " + sppuuid);
31 |
32 | try {
33 | transactCore = connectedDevice.createRfcommSocketToServiceRecord(sppuuid);
34 | } catch (IOException e) {
35 | Log.i(TAG, "[devybt sppconnection] createRfcommSocketToServiceRecord IOException");
36 | throw new BluetoothConnectionException("createRfcommSocketToServiceRecord exception", e);
37 | }
38 |
39 | // test code
40 | // if(exeCount % 2 == 0){
41 | // try {
42 | // Thread.sleep(24*1000);
43 | // } catch (InterruptedException e1) {
44 | // e1.printStackTrace();
45 | // }
46 | // }
47 | //
48 | // exeCount++;
49 |
50 | try {
51 | if(!isCancel() && transactCore != null){
52 | transactCore.connect();
53 | if(transactCore.isConnected()){
54 | onConnected();
55 | }
56 | }
57 | } catch (IOException e) {
58 | closeTransactCore();
59 | Log.i(TAG, "[devybt sppconnection] try connect IOException");
60 | throw new BluetoothConnectionException("spp connect exception" , e);
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/spp/SPPMessageParser.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.spp;
2 |
3 | import com.devyok.bluetooth.connection.BluetoothConnection.Protocol;
4 | import com.devyok.bluetooth.message.BluetoothMessage;
5 |
6 | import android.bluetooth.BluetoothDevice;
7 | /**
8 | * @author wei.deng
9 | */
10 | public interface SPPMessageParser {
11 |
12 | public BluetoothMessage[] parse(byte[] buffer, int readCount, Protocol protocol, BluetoothDevice device);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/spp/SPPMessageReceiver.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.spp;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 |
7 | import com.devyok.bluetooth.connection.BluetoothConnection.Protocol;
8 | import com.devyok.bluetooth.message.BluetoothMessage;
9 | import com.devyok.bluetooth.message.BluetoothMessageDispatcher;
10 | import com.devyok.bluetooth.utils.BluetoothUtils;
11 |
12 | import android.bluetooth.BluetoothDevice;
13 | import android.bluetooth.BluetoothSocket;
14 | import android.util.Log;
15 | /**
16 | * @author wei.deng
17 | */
18 | public class SPPMessageReceiver extends Thread{
19 |
20 | private static final String TAG = SPPMessageReceiver.class.getSimpleName();
21 |
22 | private InputStream mInStream;
23 | private OutputStream mOutStream;
24 | private volatile boolean isStopped = false;
25 | private SPPBluetoothMessageParser> messageParser;
26 | private BluetoothDevice bluetoothDevice;
27 |
28 | public SPPMessageReceiver(BluetoothSocket socket,SPPBluetoothMessageParser> parser,BluetoothDevice bluetoothDevice) {
29 | Log.i(TAG, "create SPPMessageReader");
30 |
31 | this.messageParser = parser;
32 | this.bluetoothDevice = bluetoothDevice;
33 | InputStream tmpIn = null;
34 | OutputStream tmpOut = null;
35 |
36 | try {
37 | tmpIn = socket.getInputStream();
38 | tmpOut = socket.getOutputStream();
39 | } catch (IOException e) {
40 | Log.e(TAG, "temp sockets not created", e);
41 | }
42 |
43 | mInStream = tmpIn;
44 | mOutStream = tmpOut;
45 | }
46 |
47 | public void run() {
48 | Log.i(TAG, "SPPMessageReceiver run");
49 | byte[] buffer = new byte[512];
50 | int bytes;
51 |
52 | while (!isStopped()) {
53 | try {
54 | bytes = mInStream.read(buffer);
55 |
56 | BluetoothMessage>[] messages = messageParser.parse(buffer, bytes,Protocol.SPP,this.bluetoothDevice);
57 |
58 | if(messages!=null){
59 |
60 | for (int i = 0; i < messages.length; i++) {
61 | BluetoothMessage> message = messages[i];
62 | message.setBluetoothDevice(this.bluetoothDevice);
63 | BluetoothMessageDispatcher.dispatch(message);
64 | }
65 |
66 | }
67 |
68 | } catch (IOException e) {
69 | Log.e(TAG, "disconnected", e);
70 | closeStream();
71 | break;
72 | }
73 | }
74 | Log.i(TAG, "SPPMessageReceiver run completed");
75 | }
76 |
77 | public void startReceiver() {
78 | isStopped = false;
79 | super.start();
80 | }
81 |
82 | public void stopReceiver(){
83 | isStopped = true;
84 | closeStream();
85 | }
86 |
87 | public boolean isStopped(){
88 | return isStopped;
89 | }
90 |
91 | public void closeStream() {
92 | try {
93 | BluetoothUtils.close(mInStream);
94 | BluetoothUtils.close(mOutStream);
95 | } finally {
96 | mInStream = null;
97 | mOutStream = null;
98 | }
99 |
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/java/com/devyok/bluetooth/spp/SppConnectionLoopChannelPolicy.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.spp;
2 |
3 | import java.io.IOException;
4 | import java.lang.reflect.Method;
5 | import java.util.UUID;
6 |
7 | import android.bluetooth.BluetoothDevice;
8 | import android.bluetooth.BluetoothSocket;
9 | import android.util.Log;
10 |
11 | import com.devyok.bluetooth.connection.BluetoothConnectionException;
12 | /**
13 | * @author wei.deng
14 | */
15 | public class SppConnectionLoopChannelPolicy extends AbstractSPPConnection {
16 |
17 | static final String TAG = SppConnectionLoopChannelPolicy.class.getSimpleName();
18 |
19 | int maxChannel = 3;
20 |
21 | public SppConnectionLoopChannelPolicy(UUID sppuuid,BluetoothDevice connectedDevice,int maxChannel){
22 | super(sppuuid,connectedDevice);
23 | this.maxChannel = maxChannel;
24 | }
25 |
26 | public SppConnectionLoopChannelPolicy(){
27 | this(null,null,10);
28 | }
29 |
30 | public SppConnectionLoopChannelPolicy(UUID sppuuid,BluetoothDevice connectedDevice){
31 | super(sppuuid,connectedDevice);
32 | }
33 |
34 | @Override
35 | public void connect(UUID sppuuid,BluetoothDevice connectedDevice) throws BluetoothConnectionException {
36 | BluetoothConnectionException excp = null;
37 |
38 | for (int channel = 1; channel < maxChannel; channel++) {
39 | try {
40 |
41 | if(isCancel()){
42 | break;
43 | }
44 |
45 | Method m = connectedDevice.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
46 | transactCore = (BluetoothSocket) m.invoke(connectedDevice, channel);
47 |
48 | if(transactCore != null){
49 | Log.i(TAG, "[devybt sppconnection] LoopChannelSppConnectPolicy start try connect channel("+channel+") , isCancel("+isCancel()+")");
50 |
51 | transactCore.connect();
52 |
53 | Log.i(TAG,"[devybt sppconnection] connect channel("+channel+") result" + (transactCore!=null && transactCore.isConnected() ? "success" : "fail"));
54 |
55 | } else {
56 | Log.i(TAG,"[devybt sppconnection] connect channel("+channel+") bluetoothSocket(null)");
57 | }
58 |
59 | } catch (IOException e) {
60 | Log.i(TAG, "[devybt sppconnection] IOException try connect channel("+channel+") fail");
61 | if(excp == null) {
62 | excp = new BluetoothConnectionException("try connect channel fail",e);
63 | }
64 |
65 | closeTransactCore();
66 |
67 | } catch (Exception e){
68 | Log.i(TAG, "[devybt sppconnection] Exception try connect channel("+channel+") fail");
69 | throw new BluetoothConnectionException("try connect channel exception",e);
70 | }
71 | }
72 | throw excp == null ? new BluetoothConnectionException("LoopChannelSppConnectPolicy fail") : excp;
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/res/layout/okbt_audio_device_list.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/res/layout/okbt_audio_device_list_item.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
19 |
20 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/res/values/okbt_colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #2C3E50
5 |
6 |
--------------------------------------------------------------------------------
/okbluetooth/src/main/res/values/okbt_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 扬声器
5 | 听筒
6 | 蓝牙设备
7 |
8 |
9 |
--------------------------------------------------------------------------------
/okbluetooth_demo/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/okbluetooth_demo/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/okbluetooth_demo/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | defaultConfig {
6 | applicationId "com.devyok.bluetooth.demo"
7 | minSdkVersion 19
8 | targetSdkVersion 23
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | compile project(path: ':okbluetooth')
24 | }
25 |
--------------------------------------------------------------------------------
/okbluetooth_demo/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/okbluetooth_demo/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
10 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/okbluetooth_demo/app/src/main/java/com/devyok/bluetooth/demo/DemoApplication.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.demo;
2 |
3 | import android.app.Application;
4 |
5 | public class DemoApplication extends Application {
6 |
7 | @Override
8 | public void onCreate() {
9 | super.onCreate();
10 |
11 | OkBluetoothAdapter.onAppReady(this);
12 |
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/okbluetooth_demo/app/src/main/java/com/devyok/bluetooth/demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.demo;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.view.View.OnClickListener;
8 |
9 | import com.devyok.bluetooth.OkBluetooth;
10 | import com.devyok.bluetooth.debug.DebugUIConsoleActivity;
11 |
12 | public class MainActivity extends Activity implements OnClickListener{
13 | static final String TAG = MainActivity.class.getSimpleName();
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_main);
19 |
20 | this.findViewById(R.id.start_debug_ui_console).setOnClickListener(this);
21 |
22 | }
23 |
24 | @Override
25 | public void onClick(View v) {
26 | int id = v.getId();
27 | if(R.id.start_debug_ui_console == id){
28 |
29 | Intent impl = new Intent(OkBluetooth.getContext(),DebugUIConsoleActivity.class);
30 |
31 | impl.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
32 | OkBluetooth.getContext().startActivity(impl);
33 |
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/okbluetooth_demo/app/src/main/java/com/devyok/bluetooth/demo/OkBluetoothAdapter.java:
--------------------------------------------------------------------------------
1 | package com.devyok.bluetooth.demo;
2 |
3 | import java.util.ArrayList;
4 | import java.util.concurrent.ConcurrentHashMap;
5 | import java.util.regex.Matcher;
6 | import java.util.regex.Pattern;
7 |
8 | import android.bluetooth.BluetoothDevice;
9 | import android.content.BroadcastReceiver;
10 | import android.content.Context;
11 | import android.content.Intent;
12 | import android.content.IntentFilter;
13 | import android.media.AudioManager;
14 | import android.os.Build;
15 | import android.util.Log;
16 |
17 | import com.devyok.bluetooth.AudioDevice;
18 | import com.devyok.bluetooth.Configuration;
19 | import com.devyok.bluetooth.OkBluetooth;
20 | import com.devyok.bluetooth.OkBluetooth.BluetoothProtocolConnectionStateListener;
21 | import com.devyok.bluetooth.OkBluetooth.ConnectionMode;
22 | import com.devyok.bluetooth.OkBluetooth.Interceptor;
23 | import com.devyok.bluetooth.connection.BluetoothConnection.Protocol;
24 | import com.devyok.bluetooth.message.BluetoothMessage;
25 | import com.devyok.bluetooth.message.BluetoothMessageReceiver;
26 | import com.devyok.bluetooth.spp.SPPBluetoothMessageParser;
27 | import com.devyok.bluetooth.utils.BluetoothUtils;
28 |
29 | public final class OkBluetoothAdapter {
30 |
31 | private static final String TAG = OkBluetoothAdapter.class.getSimpleName();
32 |
33 | private static final ConcurrentHashMap gInterceptors = new ConcurrentHashMap<>();
34 |
35 | static {
36 | gInterceptors.put("phoneModel", new DemoInterceptor());
37 | }
38 |
39 | public static void onAppReady(Context context){
40 |
41 | Log.i(TAG,"device mode = " + Build.MODEL);
42 |
43 | Configuration configuration = new Configuration.Builder()
44 | .setDebug(true)
45 | .setSupport(true)
46 | .setCompanyId(85)
47 | .setConnectionMode(ConnectionMode.BLUETOOTH_WIREDHEADSET_SPEAKER)
48 | .setForceTypes(OkBluetooth.FORCE_TYPE_PHONE_INCALL |
49 | OkBluetooth.FORCE_TYPE_PHONE_RING |
50 | OkBluetooth.FORCE_TYPE_PHONE_INCALL_TO_IDLE)
51 | .build();
52 |
53 |
54 | OkBluetooth.init(context.getApplicationContext(), configuration);
55 |
56 | Interceptor interceptor = gInterceptors.get(Build.MODEL);
57 |
58 | OkBluetooth.setInterceptor(interceptor);
59 | OkBluetooth.registerBluetoothProtocolConnectionStateListener(new BluetoothProtocolConnectionStateListener() {
60 |
61 | @Override
62 | public void onDisconnected(Protocol protocol, BluetoothDevice device) {
63 | super.onDisconnected(protocol, device);
64 | Log.i("btMessage", "onDisconnected protocol = " + protocol.getName() + " , device = " + device.getName());
65 | }
66 |
67 | @Override
68 | public void onConnected(Protocol protocol, BluetoothDevice device) {
69 | super.onConnected(protocol, device);
70 | Log.i("btMessage", "onConnected protocol = " + protocol.getName() + " , device = " + device.getName());
71 | }
72 |
73 | });
74 |
75 | OkBluetooth.registerBluetoothMessageParser(new SavoxSppMessageParser());
76 |
77 | OkBluetooth.registerBluetoothMessageReceiver(new BluetoothMessageReceiver() {
78 |
79 | @Override
80 | public boolean onReceive(BluetoothMessage message) {
81 | String bodyData = message.getBodyData();
82 |
83 | Log.i("btMessage", "body data = " + bodyData);
84 |
85 | return false;
86 | }
87 |
88 | },new Protocol[]{Protocol.SPP,Protocol.HFP});
89 |
90 | context.registerReceiver(new BroadcastReceiver() {
91 |
92 | @Override
93 | public void onReceive(Context context, Intent intent) {
94 |
95 | int streamType = intent.getIntExtra("android.media.EXTRA_VOLUME_STREAM_TYPE", -1);
96 |
97 | Log.i("volumnTrace", "volumn changed stream type = " + BluetoothUtils.getAudioStreamTypeString(streamType));
98 |
99 | }
100 | }, new IntentFilter("android.media.VOLUME_CHANGED_ACTION"));
101 |
102 | }
103 |
104 | static class SavoxSppMessageParser implements SPPBluetoothMessageParser {
105 |
106 | final Pattern pattern = Pattern.compile("\\W?\\w+=\\w{1}");
107 |
108 | @Override
109 | public BluetoothMessage[] parse(byte[] buffer,int readCount,Protocol protocol,BluetoothDevice device) {
110 | String data = new String(buffer, 0, readCount);
111 | Log.i("btMessage", "receiver data = " + data);
112 | Matcher matcher = pattern.matcher(data);
113 | ArrayList> result = new ArrayList<>();
114 | while(matcher.find()){
115 | result.add(BluetoothMessage.obtain(matcher.group(), protocol));
116 | }
117 |
118 | return result.toArray(new BluetoothMessage[]{});
119 | }
120 |
121 | }
122 |
123 | static class DemoInterceptor extends Interceptor {
124 |
125 | @Override
126 | public boolean beforeConnect(AudioDevice audioDevice) {
127 |
128 | if(AudioDevice.SCO == audioDevice) {
129 | // handleConnectSco();
130 | // return true;
131 | }
132 |
133 | return super.beforeConnect(audioDevice);
134 | }
135 |
136 | private static void handleConnectSco(){
137 | boolean isAudioConnected = OkBluetooth.HFP.isAudioConnected();
138 | boolean isBluetoothScoOn = OkBluetooth.isBluetoothScoOn();
139 | boolean isBluetoothA2dpOn = OkBluetooth.isBluetoothA2dpOn();
140 | boolean isSpeakerphoneOn = OkBluetooth.isSpeakerphoneOn();
141 |
142 | Log.i(TAG, "intercept tryBuildAudioConnection(SCO) isAudioConnected = " + isAudioConnected + " , isBluetoothScoOn = " + isBluetoothScoOn + " , isBluetoothA2dpOn = " + isBluetoothA2dpOn + " , isSpeakerphoneOn = " + isSpeakerphoneOn);
143 | if(!isAudioConnected) {
144 | syncSetMode(AudioManager.MODE_IN_CALL);
145 |
146 | OkBluetooth.setSpeakerphoneOn(false);
147 | OkBluetooth.setBluetoothA2dpOn(false);
148 | OkBluetooth.setBluetoothScoOn(false);
149 | syncConnectAudio();
150 | OkBluetooth.setScoStreamVolumn(OkBluetooth.getScoMaxStreamVolumn(), AudioManager.FLAG_PLAY_SOUND);
151 | } else {
152 |
153 | if(isBluetoothA2dpOn){
154 | OkBluetooth.setBluetoothA2dpOn(false);
155 | }
156 | if(isSpeakerphoneOn){
157 | OkBluetooth.setSpeakerphoneOn(false);
158 | }
159 | if(!isBluetoothScoOn) {
160 | OkBluetooth.setBluetoothScoOn(true);
161 | }
162 |
163 | }
164 | }
165 |
166 | private static void syncSetMode(int mode){
167 | Log.i(TAG, "syncSetMode("+BluetoothUtils.getAudioModeString(mode)+")");
168 | Intent intent = new Intent("com.zed3.action.SET_SYSTEM_AUDIO_MODE");
169 | intent.putExtra("com.zed3.extra.AUDIO_MODE", mode);
170 | OkBluetooth.getContext().sendBroadcast(intent);
171 |
172 | int newmode = OkBluetooth.getAudioMode();
173 | int max = 5;
174 | int cur = 0;
175 | while(newmode != mode) {
176 | if(cur >= max){
177 | break;
178 | }
179 | try {
180 | Thread.sleep(300);
181 | } catch (InterruptedException e) {
182 | e.printStackTrace();
183 | }
184 |
185 | newmode = OkBluetooth.getAudioMode();
186 |
187 | Log.i(TAG, "loop item wait new mode("+BluetoothUtils.getAudioModeString(newmode)+")");
188 | ++cur;
189 | }
190 |
191 | }
192 |
193 | private static void syncConnectAudio(){
194 | OkBluetooth.HFP.connectAudio();
195 |
196 | int max = 5;
197 | int cur = 0;
198 |
199 | boolean isAudioConnected = OkBluetooth.HFP.isAudioConnected();
200 |
201 | Log.i(TAG, "syncConnectAudio("+isAudioConnected+")");
202 |
203 | while(!isAudioConnected) {
204 | if(cur >= max){
205 | break;
206 | }
207 | try {
208 | Thread.sleep(300);
209 | } catch (InterruptedException e) {
210 | e.printStackTrace();
211 | }
212 |
213 | isAudioConnected = OkBluetooth.HFP.isAudioConnected();
214 |
215 | Log.i(TAG, "loop item wait new audio state("+isAudioConnected+")");
216 | ++cur;
217 | }
218 |
219 | }
220 |
221 | }
222 |
223 |
224 |
225 |
226 | }
227 |
--------------------------------------------------------------------------------
/okbluetooth_demo/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
16 |
21 |
26 |
31 |
36 |
41 |
46 |
51 |
56 |
61 |
66 |
71 |
76 |
81 |
86 |
91 |
96 |
101 |
106 |
111 |
116 |
121 |
126 |
131 |
136 |
141 |
146 |
151 |
156 |
161 |
166 |
171 |
172 |
--------------------------------------------------------------------------------
/okbluetooth_demo/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
14 |
15 |
--------------------------------------------------------------------------------
/okbluetooth_demo/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/okbluetooth_demo/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | BluetoothDemo
3 |
4 |
--------------------------------------------------------------------------------
/okbluetooth_demo/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.0'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/okbluetooth_demo/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1024m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/okbluetooth_demo/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devyok/OkBluetooth/49be79259c5e935f9eb8ad1f47f1c5dc6ba0a74d/okbluetooth_demo/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/okbluetooth_demo/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Aug 07 09:46:06 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/okbluetooth_demo/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/okbluetooth_demo/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/okbluetooth_demo/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/okbluetooth_demo/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devyok/OkBluetooth/49be79259c5e935f9eb8ad1f47f1c5dc6ba0a74d/okbluetooth_demo/test.jpg
--------------------------------------------------------------------------------