于林 發表於 2024-1-13 09:14:00

Android Bluetooth 蓝牙开发/蓝牙协议 小结

<h5 id="蓝牙术语">蓝牙术语</h5>
<p>RK3399 蓝牙打不开问题--解题思路<br>
蓝牙</p>
<pre><code>蓝牙术语:
HFP(Hands-free Profile)耳机模式:
让蓝牙设备可以控制电话,如接听、挂断、拒接、语音拨号等,拒接、语音拨号要视蓝牙耳机及电话是否支持。

HSP(Handset Profile)耳机模式
用于支持蓝牙耳机与移动电话之间使用

蓝牙电话广播:
BluetoothHeadsetClient.ACTION_CALL_CHANGED
public static final String ACTION_CALL_CHANGED = "android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED";

BluetoothHeadsetClientCall callStatus = intent.getParcelableExtra(BluetoothHeadsetClient.EXTRA_CALL);
      CALL_STATE_ACTIVE = 0; talking
      CALL_STATE_DIALING = 2; CALL_STATE_ALERTING = 3; out dial
      CALL_STATE_WAITING = 5; waiting
      CALL_STATE_INCOMING = 4; incoming
      CALL_STATE_TERMINATED = 7; hangup

蓝牙电话手机和耳机音频切换广播:
BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED
public static final String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED";
int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                BluetoothProfile.STATE_DISCONNECTED);
newState :2 bt
newState :0 phone

(https://blog.csdn.net/weixin_45534242/article/details/124899251)
BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_AUDIO_STATE_CHANGED =
            "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";

    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_ACTIVE_DEVICE_CHANGED =
            "android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED";


</code></pre>
<h5 id="获取蓝牙-pbap-协议栈的支持">获取蓝牙 Pbap 协议栈的支持</h5>
<p>蓝牙开发相关协议<br>
Android 蓝牙开发——PBAP协议(十)<br>
BluetoothPbapClient</p>
<pre><code>为了方便开发,Android 提供了若干个蓝牙功能的协议栈,我们称之为 profile 。车机蓝牙开发我们需要用到的 profile 主要有:
Profile             Description
A2DP Sink       音频相关
HFP Client       电话相关
Avrcp Controller       音频控制相关
Pbap Client                通讯录、通话记录相关

</code></pre>
<h5 id="android--蓝牙-app开发--函数回调">Android蓝牙 app开发函数回调</h5>
<pre><code>//\frameworks\base\packages\SettingsLib\src\com\android\settingslib\bluetooth
public class TextApiActivity extends Activity {
    private static final String TAG = "TextApiActivity";

    private LocalBluetoothManager mLocalBluetoothManager;
    private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager;
    private BluetoothEventManager mBluetoothEventManager;
    private LocalBluetoothProfileManager mBluetoothProfileManager;


    private LocalBluetoothAdapter mLocalBluetoothAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_text_api);
      mLocalBluetoothManager = getLocalBtManager(TextApiActivity.this);

      mCachedBluetoothDeviceManager = mLocalBluetoothManager.getCachedDeviceManager();
      mBluetoothEventManager = mLocalBluetoothManager.getEventManager();
      mBluetoothProfileManager = mLocalBluetoothManager.getProfileManager();

      mBluetoothEventManager.registerCallback(mBluetoothCallback);
      mBluetoothProfileManager.addServiceListener(mServiceListener);


      mLocalBluetoothAdapter = mLocalBluetoothManager.getBluetoothAdapter();

      findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mLocalBluetoothAdapter != null) {
                  mLocalBluetoothAdapter.startScanning(true);
                }
            }
      });
    }


    public static LocalBluetoothManager getLocalBtManager(Context context) {
      return LocalBluetoothManager.getInstance(context, mOnInitCallback);
    }

    private static final LocalBluetoothManager.BluetoothManagerCallback mOnInitCallback =
            new LocalBluetoothManager.BluetoothManagerCallback() {
                @Override
                public void onBluetoothManagerInitialized(Context appContext, LocalBluetoothManager bluetoothManager) {
                  BluetoothUtils.setErrorListener(mErrorListener);
                }
            };


    //监听协议(Profile)相关接口是否可用
    LocalBluetoothProfileManager.ServiceListener mServiceListener = new LocalBluetoothProfileManager.ServiceListener() {
      @Override
      public void onServiceConnected() {
            //Bluetooth Service bind success 可以调用各Profile的接口
      }

      @Override
      public void onServiceDisconnected() {
            //Bluetooth Service unbind success

      }
    };


    BluetoothCallback mBluetoothCallback = new BluetoothCallback() {
      @Override
      public void onBluetoothStateChanged(int bluetoothState) {
            //蓝牙开关状态变化
            Log.d(TAG, "onBluetoothStateChanged:" + bluetoothState);
            BluetoothCallback.super.onBluetoothStateChanged(bluetoothState);
      }

      @Override
      public void onScanningStateChanged(boolean started) {
            //搜索状态变化
            Log.d(TAG, "onScanningStateChanged:" + started);
            BluetoothCallback.super.onScanningStateChanged(started);
      }

      @Override
      public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
            //搜索到新设备
            Log.d(TAG, "onDeviceAdded:" + cachedDevice.getName());
            BluetoothCallback.super.onDeviceAdded(cachedDevice);
      }

      @Override
      public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
            //设备被移除
            Log.d(TAG, "onDeviceDeleted:" + cachedDevice.getName());
            BluetoothCallback.super.onDeviceDeleted(cachedDevice);
      }

      @Override
      public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
            //设备配对状态变化
            Log.d(TAG, "onDeviceBondStateChanged:" + cachedDevice.getName() + "-----》" + bondState);
            BluetoothCallback.super.onDeviceBondStateChanged(cachedDevice, bondState);
      }

      @Override
      public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
            //设备连接状态变化
            Log.d(TAG, "onConnectionStateChanged:" + cachedDevice.getName() + "-----》" + state);
            BluetoothCallback.super.onConnectionStateChanged(cachedDevice, state);
      }

      @Override
      public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
            //活动设备变化
            Log.d(TAG, "onConnectionStateChanged:" + activeDevice.getName() + "bluetoothProfile-----》" + bluetoothProfile);
            BluetoothCallback.super.onActiveDeviceChanged(activeDevice, bluetoothProfile);
      }

      @Override
      public void onAudioModeChanged() {
            BluetoothCallback.super.onAudioModeChanged();
      }

      @Override
      public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, int bluetoothProfile) {
            //协议连接状态变化
            BluetoothCallback.super.onProfileConnectionStateChanged(cachedDevice, state, bluetoothProfile);
      }

      @Override
      public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
            //ACL连接状态变化
            BluetoothCallback.super.onAclConnectionStateChanged(cachedDevice, state);
      }
    };

    private static final ErrorListener mErrorListener = new ErrorListener() {
      @Override
      public void onShowError(Context context, String name, int messageResId) {
            showError(context, name, messageResId);
      }
    };

    static void showError(Context context, String name, int messageResId) {
      showError(context, name, messageResId, getLocalBtManager(context));
    }

    private static void showError(Context context, String name, int messageResId, LocalBluetoothManager manager) {
      String message = context.getString(messageResId, name);
      if (manager.isForegroundActivity()) {
            try {
                Log.d(TAG, "show ErrorDialogFragment, message is " + message);

            } catch (Exception e) {
                Log.e(TAG, "Cannot show error dialog.", e);
            }
      } else {
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
      }
    }
}

</code></pre>
<h5 id="android--蓝牙-app开发--电话范例---反射">Android蓝牙 app开发电话范例 --&gt;反射</h5>
<p>demo</p>
<pre><code>那么Android手机设备通过蓝牙连接上汽车中控系统后,如何实现打电话功能的?有两种方式实现
1.通过硬件厂商提供的SDK来实现,这部分直接调用提供的API即可,实现简单
2.通过标准的Android 蓝牙协议实现,需要自己来实现,网上这方面的文章也不是很多

通过标准的Android蓝牙如何实现打电话的?
android.bluetooth.BluetoothHeadsetClient是一个系统隐藏类,实现蓝牙电话就是通过这个类完成。
不能直接调用,就只能反射调用了:
public class BluetoothManager {
    private final static String DIAL_CLASS_NAME = "android.bluetooth.BluetoothHeadsetClient";//拨打电话类名
    private final static String DIAL_METHOD_NAME = "dial";//拨打电话方法名
    private final static String BLUE_TOOTH_PROFILE_FIELD = "HEADSET_CLIENT";//蓝牙适配器远程设备类型

    private static BluetoothManager instance;
    private OnCallResultListener onCallResultListener;

    public interface OnCallResultListener {
      //蓝牙未打开
      void onBluetoothIsClosed();

      //蓝牙未连接
      void onDeviceIsEmpty();

      //无效的电话号码
      void onPhoneIsInValid();

      void onError(String errorMsg);
    }

    public static BluetoothManager getInstance() {
      if (instance == null) {
            instance = new BluetoothManager();
      }
      return instance;
    }

    //拨打电话的实际调用
    public void dial(final String number, final OnCallResultListener onCallResultListener) {
      this.onCallResultListener = onCallResultListener;
      if (StringUtils.isEmpty(number)) {
            if (onCallResultListener != null) {
                onCallResultListener.onPhoneIsInValid();
            }
      }
      getConnectStatus(new BluetoothProfile.ServiceListener() {
            @Override
            public void onServiceConnected(int profile, BluetoothProfile proxy) {
                List&lt;BluetoothDevice&gt; mDevices = proxy.getConnectedDevices();
                if (!Utils.isListEmpty(mDevices)) {
                  for (BluetoothDevice device : mDevices) {
                        dial(proxy, device, number);
                        break;
                  }
                } else {
                  if (onCallResultListener != null) {
                        onCallResultListener.onDeviceIsEmpty();
                  }
                }
            }

            @Override
            public void onServiceDisconnected(int profile) {
                if (onCallResultListener != null) {
                  onCallResultListener.onDeviceIsEmpty();
                }
            }
      });
    }

    //获取蓝牙的连接状态
    private void getConnectStatus(BluetoothProfile.ServiceListener serviceListener) {
      final int bluetooth_Profile_HEADSET_CLIENT;
      try {
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            if (!adapter.isEnabled()) {
                if (onCallResultListener != null) {
                  onCallResultListener.onBluetoothIsClosed();
                  return;
                }
            }

            bluetooth_Profile_HEADSET_CLIENT = (int) BluetoothProfile.class.getField(BLUE_TOOTH_PROFILE_FIELD).get(null);
            //获取到蓝牙电话的连接状态
            int isConnected = adapter.getProfileConnectionState(bluetooth_Profile_HEADSET_CLIENT);
            if (isConnected == BluetoothProfile.STATE_DISCONNECTED) {
                if (onCallResultListener != null) {
                  onCallResultListener.onDeviceIsEmpty();
                  return;
                }
            }
            adapter.getProfileProxy(CommonApp.getCommonApp().getApplication(), serviceListener, bluetooth_Profile_HEADSET_CLIENT);

      } catch (Exception e) {
            if (onCallResultListener != null) {
                onCallResultListener.onError(e.getMessage());
            }
      }
    }

    /***
   * 拨号
   * @param proxy
   * @param bluetoothDevice
   * @param number
   */
    private void dial(BluetoothProfile proxy, BluetoothDevice bluetoothDevice, String number) {
      try {
            if (proxy == null || bluetoothDevice == null || (StringUtils.isEmpty(number))) {
                return;
            }
            Class BluetoothHeadsetClient = Class.forName(DIAL_CLASS_NAME);
            Method methodMain = BluetoothHeadsetClient.getMethod(DIAL_METHOD_NAME, BluetoothDevice.class, String.class);
            if (methodMain != null) {
                //蓝牙电话调用的具体执行
                methodMain.invoke(proxy, bluetoothDevice, number);
            }
      } catch (Exception e) {
            if (onCallResultListener != null) {
                onCallResultListener.onError(e.getMessage());
            }
      }
    }
}

//如果有系统源码,采用定制化的系统,直接引入out下面的framework.jar
private void createBtHeadSetClient() {
      BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
      if (bluetoothAdapter != null) {
            bluetoothAdapter.getProfileProxy(getApplicationContext(), new BluetoothProfile.ServiceListener() {
                @Override
                public void onServiceConnected(int profile, BluetoothProfile proxy) {
                  if (profile == BluetoothProfile.HEADSET_CLIENT) {
                        Log.d(TAG, "bluetoothAdapter onServiceConnected proxy:" + proxy);
                        mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
                  }
                }

                @Override
                public void onServiceDisconnected(int profile) {
                  Log.d(TAG, "bluetoothAdapter onServiceDisconnected" + profile);
                }
            }, BluetoothProfile.HEADSET_CLIENT);
      }
    }
   
public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) {
   
}

</code></pre>
<h3 id="android-90-设置去取热点打开的首页显示的提示">Android 9.0 设置去取热点打开的首页显示的提示</h3>
<pre><code>--- a/ac8257_0302/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/dashboard/conditional/ConditionManager.java
+++ b/ac8257_0302/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/dashboard/conditional/ConditionManager.java
@@ -42,7 +42,7 @@ public class ConditionManager implements LifecycleObserver, OnResume, OnPause {

   private static final String TAG = "ConditionManager";

-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = true;

   private static final String PKG = "com.android.settings.dashboard.conditional.";

@@ -176,7 +176,9 @@ public class ConditionManager implements LifecycleObserver, OnResume, OnPause {
         if (AirplaneModeCondition.class == clz) {
             return new AirplaneModeCondition(this);
         } else if (HotspotCondition.class == clz) {
-            return new HotspotCondition(this);
+            //return new HotspotCondition(this);//add
+            Log.d(TAG,"no new HotspotCondition(this)");
+            return null;
         } else if (DndCondition.class == clz) {
             return new DndCondition(this);
         } else if (BatterySaverCondition.class == clz) {
</code></pre><br><br>
来源:https://www.cnblogs.com/kato-T/p/17961954
頁: [1]
查看完整版本: Android Bluetooth 蓝牙开发/蓝牙协议 小结