Guest User

Untitled

a guest
Dec 17th, 2018
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.71 KB | None | 0 0
  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5.  
  6. package com.quickblox.videochat.webrtc;
  7.  
  8. import android.annotation.SuppressLint;
  9. import android.bluetooth.BluetoothAdapter;
  10. import android.bluetooth.BluetoothDevice;
  11. import android.bluetooth.BluetoothHeadset;
  12. import android.bluetooth.BluetoothProfile;
  13. import android.bluetooth.BluetoothProfile.ServiceListener;
  14. import android.content.BroadcastReceiver;
  15. import android.content.Context;
  16. import android.content.Intent;
  17. import android.content.IntentFilter;
  18. import android.media.AudioManager;
  19. import android.os.Handler;
  20. import android.os.Looper;
  21. import android.os.Process;
  22. import com.quickblox.videochat.webrtc.util.Logger;
  23. import java.util.Iterator;
  24. import java.util.List;
  25. import java.util.Set;
  26. import org.webrtc.ThreadUtils;
  27.  
  28. class AppRTCBluetoothManager {
  29. private static final String TAG = AppRTCBluetoothManager.class.getSimpleName();
  30. private static final Logger LOGGER;
  31. private static final int BLUETOOTH_SCO_TIMEOUT_MS = 4000;
  32. private static final int MAX_SCO_CONNECTION_ATTEMPTS = 2;
  33. private final Context apprtcContext;
  34. private final AppRTCAudioManager apprtcAudioManager;
  35. private final AudioManager audioManager;
  36. private final Handler handler;
  37. int scoConnectionAttempts;
  38. private AppRTCBluetoothManager.State bluetoothState;
  39. private final ServiceListener bluetoothServiceListener;
  40. private BluetoothAdapter bluetoothAdapter;
  41. private BluetoothHeadset bluetoothHeadset;
  42. private BluetoothDevice bluetoothDevice;
  43. private final BroadcastReceiver bluetoothHeadsetReceiver;
  44. private final Runnable bluetoothTimeoutRunnable = new Runnable() {
  45. public void run() {
  46. AppRTCBluetoothManager.this.bluetoothTimeout();
  47. }
  48. };
  49.  
  50. static AppRTCBluetoothManager create(Context context, AppRTCAudioManager audioManager) {
  51. LOGGER.d(TAG, "create" + AppRTCUtils.getThreadInfo());
  52. return new AppRTCBluetoothManager(context, audioManager);
  53. }
  54.  
  55. private AppRTCBluetoothManager(Context context, AppRTCAudioManager audioManager) {
  56. ThreadUtils.checkIsOnMainThread();
  57. this.apprtcContext = context;
  58. this.apprtcAudioManager = audioManager;
  59. this.audioManager = this.getAudioManager(context);
  60. this.bluetoothState = AppRTCBluetoothManager.State.UNINITIALIZED;
  61. this.bluetoothServiceListener = new AppRTCBluetoothManager.BluetoothServiceListener();
  62. this.bluetoothHeadsetReceiver = new AppRTCBluetoothManager.BluetoothHeadsetBroadcastReceiver();
  63. this.handler = new Handler(Looper.getMainLooper());
  64. }
  65.  
  66. AppRTCBluetoothManager.State getState() {
  67. ThreadUtils.checkIsOnMainThread();
  68. return this.bluetoothState;
  69. }
  70.  
  71. @SuppressLint({"MissingPermission"})
  72. void start() {
  73. ThreadUtils.checkIsOnMainThread();
  74. LOGGER.d(TAG, "start");
  75. if (!this.hasPermission(this.apprtcContext, "android.permission.BLUETOOTH")) {
  76. LOGGER.w(TAG, "Process (pid=" + Process.myPid() + ") lacks BLUETOOTH permission");
  77. } else if (this.bluetoothState != AppRTCBluetoothManager.State.UNINITIALIZED) {
  78. LOGGER.w(TAG, "Invalid BT state");
  79. } else {
  80. this.bluetoothHeadset = null;
  81. this.bluetoothDevice = null;
  82. this.scoConnectionAttempts = 0;
  83. this.bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  84. if (this.bluetoothAdapter == null) {
  85. LOGGER.w(TAG, "Device does not support Bluetooth");
  86. } else if (!this.audioManager.isBluetoothScoAvailableOffCall()) {
  87. LOGGER.e(TAG, "Bluetooth SCO audio is not available off call");
  88. } else {
  89. this.logBluetoothAdapterInfo(this.bluetoothAdapter);
  90. if (!this.getBluetoothProfileProxy(this.apprtcContext, this.bluetoothServiceListener, 1)) {
  91. LOGGER.e(TAG, "BluetoothAdapter.getProfileProxy(HEADSET) failed");
  92. } else {
  93. IntentFilter bluetoothHeadsetFilter = new IntentFilter();
  94. bluetoothHeadsetFilter.addAction("android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED");
  95. bluetoothHeadsetFilter.addAction("android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED");
  96. this.registerReceiver(this.bluetoothHeadsetReceiver, bluetoothHeadsetFilter);
  97. LOGGER.d(TAG, "HEADSET profile state: " + this.stateToString(this.bluetoothAdapter.getProfileConnectionState(1)));
  98. LOGGER.d(TAG, "Bluetooth proxy for headset profile has started");
  99. this.bluetoothState = AppRTCBluetoothManager.State.HEADSET_UNAVAILABLE;
  100. LOGGER.d(TAG, "start done: BT state=" + this.bluetoothState);
  101. }
  102. }
  103. }
  104. }
  105.  
  106. void stop() {
  107. ThreadUtils.checkIsOnMainThread();
  108. LOGGER.d(TAG, "stop: BT state=" + this.bluetoothState);
  109. if (this.bluetoothAdapter != null) {
  110. this.stopScoAudio();
  111. if (this.bluetoothState != AppRTCBluetoothManager.State.UNINITIALIZED) {
  112. this.unregisterReceiver(this.bluetoothHeadsetReceiver);
  113. this.cancelTimer();
  114. if (this.bluetoothHeadset != null) {
  115. this.bluetoothAdapter.closeProfileProxy(1, this.bluetoothHeadset);
  116. this.bluetoothHeadset = null;
  117. }
  118.  
  119. this.bluetoothAdapter = null;
  120. this.bluetoothDevice = null;
  121. this.bluetoothState = AppRTCBluetoothManager.State.UNINITIALIZED;
  122. LOGGER.d(TAG, "stop done: BT state=" + this.bluetoothState);
  123. }
  124. }
  125. }
  126.  
  127. boolean startScoAudio() {
  128. ThreadUtils.checkIsOnMainThread();
  129. LOGGER.d(TAG, "startSco: BT state=" + this.bluetoothState + ", attempts: " + this.scoConnectionAttempts + ", SCO is on: " + this.isScoOn());
  130. if (this.scoConnectionAttempts >= 2) {
  131. LOGGER.e(TAG, "BT SCO connection fails - no more attempts");
  132. return false;
  133. } else if (this.bluetoothState != AppRTCBluetoothManager.State.HEADSET_AVAILABLE) {
  134. LOGGER.e(TAG, "BT SCO connection fails - no headset available");
  135. return false;
  136. } else {
  137. LOGGER.d(TAG, "Starting Bluetooth SCO and waits for ACTION_AUDIO_STATE_CHANGED...");
  138. this.bluetoothState = AppRTCBluetoothManager.State.SCO_CONNECTING;
  139. this.audioManager.startBluetoothSco();
  140. this.audioManager.setBluetoothScoOn(true);
  141. ++this.scoConnectionAttempts;
  142. this.startTimer();
  143. LOGGER.d(TAG, "startScoAudio done: BT state=" + this.bluetoothState + ", SCO is on: " + this.isScoOn());
  144. return true;
  145. }
  146. }
  147.  
  148. void stopScoAudio() {
  149. ThreadUtils.checkIsOnMainThread();
  150. LOGGER.d(TAG, "stopScoAudio: BT state=" + this.bluetoothState + ", SCO is on: " + this.isScoOn());
  151. if (this.bluetoothState == AppRTCBluetoothManager.State.SCO_CONNECTING || this.bluetoothState == AppRTCBluetoothManager.State.SCO_CONNECTED) {
  152. this.cancelTimer();
  153. this.audioManager.stopBluetoothSco();
  154. this.audioManager.setBluetoothScoOn(false);
  155. this.bluetoothState = AppRTCBluetoothManager.State.SCO_DISCONNECTING;
  156. LOGGER.d(TAG, "stopScoAudio done: BT state=" + this.bluetoothState + ", SCO is on: " + this.isScoOn());
  157. }
  158. }
  159.  
  160. @SuppressLint({"MissingPermission"})
  161. void updateDevice() {
  162. if (this.bluetoothState != AppRTCBluetoothManager.State.UNINITIALIZED && this.bluetoothHeadset != null) {
  163. LOGGER.d(TAG, "updateDevice");
  164. List<BluetoothDevice> devices = this.bluetoothHeadset.getConnectedDevices();
  165. if (devices.isEmpty()) {
  166. this.bluetoothDevice = null;
  167. this.bluetoothState = AppRTCBluetoothManager.State.HEADSET_UNAVAILABLE;
  168. LOGGER.d(TAG, "No connected bluetooth headset");
  169. } else {
  170. this.bluetoothDevice = (BluetoothDevice)devices.get(0);
  171. this.bluetoothState = AppRTCBluetoothManager.State.HEADSET_AVAILABLE;
  172. LOGGER.d(TAG, "Connected bluetooth headset: name=" + this.bluetoothDevice.getName() + ", state=" + this.stateToString(this.bluetoothHeadset.getConnectionState(this.bluetoothDevice)) + ", SCO audio=" + this.bluetoothHeadset.isAudioConnected(this.bluetoothDevice));
  173. }
  174.  
  175. LOGGER.d(TAG, "updateDevice done: BT state=" + this.bluetoothState);
  176. }
  177. }
  178.  
  179. private AudioManager getAudioManager(Context context) {
  180. return (AudioManager)context.getSystemService("audio");
  181. }
  182.  
  183. private void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
  184. this.apprtcContext.registerReceiver(receiver, filter);
  185. }
  186.  
  187. private void unregisterReceiver(BroadcastReceiver receiver) {
  188. this.apprtcContext.unregisterReceiver(receiver);
  189. }
  190.  
  191. private boolean getBluetoothProfileProxy(Context context, ServiceListener listener, int profile) {
  192. return this.bluetoothAdapter.getProfileProxy(context, listener, profile);
  193. }
  194.  
  195. private boolean hasPermission(Context context, String permission) {
  196. return this.apprtcContext.checkPermission(permission, Process.myPid(), Process.myUid()) == 0;
  197. }
  198.  
  199. @SuppressLint({"MissingPermission"})
  200. private void logBluetoothAdapterInfo(BluetoothAdapter localAdapter) {
  201. LOGGER.d(TAG, "BluetoothAdapter: enabled=" + localAdapter.isEnabled() + ", state=" + this.stateToString(localAdapter.getState()) + ", name=" + localAdapter.getName() + ", address=" + localAdapter.getAddress());
  202. Set<BluetoothDevice> pairedDevices = localAdapter.getBondedDevices();
  203. if (!pairedDevices.isEmpty()) {
  204. LOGGER.d(TAG, "paired devices:");
  205. Iterator var3 = pairedDevices.iterator();
  206.  
  207. while(var3.hasNext()) {
  208. BluetoothDevice device = (BluetoothDevice)var3.next();
  209. LOGGER.d(TAG, " name=" + device.getName() + ", address=" + device.getAddress());
  210. }
  211. }
  212.  
  213. }
  214.  
  215. private void updateAudioDeviceState() {
  216. ThreadUtils.checkIsOnMainThread();
  217. LOGGER.d(TAG, "updateAudioDeviceState");
  218. this.apprtcAudioManager.updateAudioDeviceState();
  219. }
  220.  
  221. private void startTimer() {
  222. ThreadUtils.checkIsOnMainThread();
  223. LOGGER.d(TAG, "startTimer");
  224. this.handler.postDelayed(this.bluetoothTimeoutRunnable, 4000L);
  225. }
  226.  
  227. private void cancelTimer() {
  228. ThreadUtils.checkIsOnMainThread();
  229. LOGGER.d(TAG, "cancelTimer");
  230. this.handler.removeCallbacks(this.bluetoothTimeoutRunnable);
  231. }
  232.  
  233. @SuppressLint({"MissingPermission"})
  234. private void bluetoothTimeout() {
  235. ThreadUtils.checkIsOnMainThread();
  236. if (this.bluetoothState != AppRTCBluetoothManager.State.UNINITIALIZED && this.bluetoothHeadset != null) {
  237. LOGGER.d(TAG, "bluetoothTimeout: BT state=" + this.bluetoothState + ", attempts: " + this.scoConnectionAttempts + ", SCO is on: " + this.isScoOn());
  238. if (this.bluetoothState == AppRTCBluetoothManager.State.SCO_CONNECTING) {
  239. boolean scoConnected = false;
  240. List<BluetoothDevice> devices = this.bluetoothHeadset.getConnectedDevices();
  241. if (devices.size() > 0) {
  242. this.bluetoothDevice = (BluetoothDevice)devices.get(0);
  243. if (this.bluetoothHeadset.isAudioConnected(this.bluetoothDevice)) {
  244. LOGGER.d(TAG, "SCO connected with " + this.bluetoothDevice.getName());
  245. scoConnected = true;
  246. } else {
  247. LOGGER.d(TAG, "SCO is not connected with " + this.bluetoothDevice.getName());
  248. }
  249. }
  250.  
  251. if (scoConnected) {
  252. this.bluetoothState = AppRTCBluetoothManager.State.SCO_CONNECTED;
  253. this.scoConnectionAttempts = 0;
  254. } else {
  255. LOGGER.w(TAG, "BT failed to connect after timeout");
  256. this.stopScoAudio();
  257. }
  258.  
  259. this.updateAudioDeviceState();
  260. LOGGER.d(TAG, "bluetoothTimeout done: BT state=" + this.bluetoothState);
  261. }
  262. }
  263. }
  264.  
  265. private boolean isScoOn() {
  266. return this.audioManager.isBluetoothScoOn();
  267. }
  268.  
  269. private String stateToString(int state) {
  270. switch(state) {
  271. case 0:
  272. return "DISCONNECTED";
  273. case 1:
  274. return "CONNECTING";
  275. case 2:
  276. return "CONNECTED";
  277. case 3:
  278. return "DISCONNECTING";
  279. case 4:
  280. case 5:
  281. case 6:
  282. case 7:
  283. case 8:
  284. case 9:
  285. default:
  286. return "INVALID";
  287. case 10:
  288. return "OFF";
  289. case 11:
  290. return "TURNING_ON";
  291. case 12:
  292. return "ON";
  293. case 13:
  294. return "TURNING_OFF";
  295. }
  296. }
  297.  
  298. static {
  299. LOGGER = Logger.getInstance(BaseClient.TAG);
  300. }
  301.  
  302. private class BluetoothHeadsetBroadcastReceiver extends BroadcastReceiver {
  303. private BluetoothHeadsetBroadcastReceiver() {
  304. }
  305.  
  306. public void onReceive(Context context, Intent intent) {
  307. if (AppRTCBluetoothManager.this.bluetoothState != AppRTCBluetoothManager.State.UNINITIALIZED) {
  308. String action = intent.getAction();
  309. int state;
  310. if (action.equals("android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED")) {
  311. state = intent.getIntExtra("android.bluetooth.profile.extra.STATE", 0);
  312. AppRTCBluetoothManager.LOGGER.d(AppRTCBluetoothManager.TAG, "BluetoothHeadsetBroadcastReceiver.onReceive: a=ACTION_CONNECTION_STATE_CHANGED, s=" + AppRTCBluetoothManager.this.stateToString(state) + ", sb=" + this.isInitialStickyBroadcast() + ", BT state: " + AppRTCBluetoothManager.this.bluetoothState);
  313. if (state == 2) {
  314. AppRTCBluetoothManager.this.scoConnectionAttempts = 0;
  315. AppRTCBluetoothManager.this.updateAudioDeviceState();
  316. } else if (state != 1 && state != 3 && state == 0) {
  317. AppRTCBluetoothManager.this.stopScoAudio();
  318. AppRTCBluetoothManager.this.updateAudioDeviceState();
  319. }
  320. } else if (action.equals("android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED")) {
  321. state = intent.getIntExtra("android.bluetooth.profile.extra.STATE", 10);
  322. AppRTCBluetoothManager.LOGGER.d(AppRTCBluetoothManager.TAG, "BluetoothHeadsetBroadcastReceiver.onReceive: a=ACTION_AUDIO_STATE_CHANGED, s=" + AppRTCBluetoothManager.this.stateToString(state) + ", sb=" + this.isInitialStickyBroadcast() + ", BT state: " + AppRTCBluetoothManager.this.bluetoothState);
  323. if (state == 12) {
  324. AppRTCBluetoothManager.this.cancelTimer();
  325. if (AppRTCBluetoothManager.this.bluetoothState == AppRTCBluetoothManager.State.SCO_CONNECTING) {
  326. AppRTCBluetoothManager.LOGGER.d(AppRTCBluetoothManager.TAG, "+++ Bluetooth audio SCO is now connected");
  327. AppRTCBluetoothManager.this.bluetoothState = AppRTCBluetoothManager.State.SCO_CONNECTED;
  328. AppRTCBluetoothManager.this.scoConnectionAttempts = 0;
  329. AppRTCBluetoothManager.this.updateAudioDeviceState();
  330. } else {
  331. AppRTCBluetoothManager.LOGGER.w(AppRTCBluetoothManager.TAG, "Unexpected state BluetoothHeadset.STATE_AUDIO_CONNECTED");
  332. }
  333. } else if (state == 11) {
  334. AppRTCBluetoothManager.LOGGER.d(AppRTCBluetoothManager.TAG, "+++ Bluetooth audio SCO is now connecting...");
  335. } else if (state == 10) {
  336. AppRTCBluetoothManager.LOGGER.d(AppRTCBluetoothManager.TAG, "+++ Bluetooth audio SCO is now disconnected");
  337. if (this.isInitialStickyBroadcast()) {
  338. AppRTCBluetoothManager.LOGGER.d(AppRTCBluetoothManager.TAG, "Ignore STATE_AUDIO_DISCONNECTED initial sticky broadcast.");
  339. return;
  340. }
  341.  
  342. AppRTCBluetoothManager.this.updateAudioDeviceState();
  343. }
  344. }
  345.  
  346. AppRTCBluetoothManager.LOGGER.d(AppRTCBluetoothManager.TAG, "onReceive done: BT state=" + AppRTCBluetoothManager.this.bluetoothState);
  347. }
  348. }
  349. }
  350.  
  351. private class BluetoothServiceListener implements ServiceListener {
  352. private BluetoothServiceListener() {
  353. }
  354.  
  355. public void onServiceConnected(int profile, BluetoothProfile proxy) {
  356. if (profile == 1 && AppRTCBluetoothManager.this.bluetoothState != AppRTCBluetoothManager.State.UNINITIALIZED) {
  357. AppRTCBluetoothManager.LOGGER.d(AppRTCBluetoothManager.TAG, "BluetoothServiceListener.onServiceConnected: BT state=" + AppRTCBluetoothManager.this.bluetoothState);
  358. AppRTCBluetoothManager.this.bluetoothHeadset = (BluetoothHeadset)proxy;
  359. AppRTCBluetoothManager.this.updateAudioDeviceState();
  360. AppRTCBluetoothManager.LOGGER.d(AppRTCBluetoothManager.TAG, "onServiceConnected done: BT state=" + AppRTCBluetoothManager.this.bluetoothState);
  361. }
  362. }
  363.  
  364. public void onServiceDisconnected(int profile) {
  365. if (profile == 1 && AppRTCBluetoothManager.this.bluetoothState != AppRTCBluetoothManager.State.UNINITIALIZED) {
  366. AppRTCBluetoothManager.LOGGER.d(AppRTCBluetoothManager.TAG, "BluetoothServiceListener.onServiceDisconnected: BT state=" + AppRTCBluetoothManager.this.bluetoothState);
  367. AppRTCBluetoothManager.this.stopScoAudio();
  368. AppRTCBluetoothManager.this.bluetoothHeadset = null;
  369. AppRTCBluetoothManager.this.bluetoothDevice = null;
  370. AppRTCBluetoothManager.this.bluetoothState = AppRTCBluetoothManager.State.HEADSET_UNAVAILABLE;
  371. AppRTCBluetoothManager.this.updateAudioDeviceState();
  372. AppRTCBluetoothManager.LOGGER.d(AppRTCBluetoothManager.TAG, "onServiceDisconnected done: BT state=" + AppRTCBluetoothManager.this.bluetoothState);
  373. }
  374. }
  375. }
  376.  
  377. public static enum State {
  378. UNINITIALIZED,
  379. ERROR,
  380. HEADSET_UNAVAILABLE,
  381. HEADSET_AVAILABLE,
  382. SCO_DISCONNECTING,
  383. SCO_CONNECTING,
  384. SCO_CONNECTED;
  385.  
  386. private State() {
  387. }
  388. }
  389. }
Add Comment
Please, Sign In to add comment