成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

鴻蒙BLE藍牙通信開發總結

原創
系統 OpenHarmony
通過BLE掃描和廣播提供的開放能力,可以根據指定狀態獲取外圍設備、啟動或停止BLE掃描、廣播、數據交互。

??想了解更多內容,請訪問:??

??51CTO和華為官方合作共建的鴻蒙技術社區??

??https://harmonyos.51cto.com??

目標

通過BLE掃描和廣播提供的開放能力,可以根據指定狀態獲取外圍設備、啟動或停止BLE掃描、廣播、數據交互。

關于BLE藍牙的掃描和廣播你可以查看官方文檔

效果

藍牙介紹

藍牙是短距離無線通信的一種方式,支持藍牙的兩個設備必須配對后才能通信。HarmonyOS藍牙主要分為傳統藍牙和低功耗藍牙(通常稱為BLE,Bluetooth Low Energy)。傳統藍牙指的是藍牙版本3.0以下的藍牙,低功耗藍牙指的是藍牙版本4.0以上的藍牙。

如果你對藍牙感興趣,可以看看 HarmonyOS 藍牙介紹或者我前面寫的一篇文章:鴻蒙關于藍牙的那些事

概念

在進入實戰之前,先說明一個BLE藍牙的通信協議,GATT【Generic Attribute Profile】,GATT 是一個在藍牙連接之上的發送和接收很短的數據段的通用規范,這些很短的數據段被稱為屬性(Attribute)。在說明GATT之前還需要知道一個GAP【Generic Access Profile】。

GAP包含:搜索藍牙設備(Discovery)、管理連接(Link establishment),還有不同的安全等級(Security)。以及從用戶層面訪問一些參數的方式。GAP給設備定義了若干角色,其中主要的兩個是:外圍設備(Peripheral)和中心設備(Central)。

  • 外圍設備:這一般就是非常小或者簡單的低功耗設備,用來提供數據,并連接到一個更加相對強大的中心設備,例如:藍牙手環。
  • 中心設備:中心設備相對比較強大,用來連接其他外圍設備,例如手機。

GATT定義兩個BLE設備通過叫做Service和Characteristic的東西進行通信,他使用了ATT(Attribute Protocol)協議,需要說明的是,GATT連接必需先經過GAP協議。

另外,特別注意的是:GATT連接是獨占的。也就是一個BLE外設同時只能被一個中心設備連接。一旦外設被連接,它就會馬上停止廣播,這樣它就對其他設備不可見了。當設備斷開,它又開始廣播。中心設備和外設需要雙向通信的話,唯一的方式就是建立GATT連接。

GATT連接的網絡拓撲

一個外設只能連接一個中心設備,而一個中心設備可以連接多個外設。中心設備負責掃描外圍設備、發現廣播。外圍設備負責發送廣播。

前置條件

一、前期準備

說明:如果需要完成藍牙間的通信則需要借助藍牙中的服務,如何獲取BLE藍牙相關的MAC地址和服務編號【uuid】可以參看我前面寫的一篇文章:鴻蒙關于藍牙的那些事

1.1、獲取外圍藍牙設備的MAC

本此講解的實戰中使用到的相關設備MAC

MAC:E2:xx:xx:xx:xx:EB

1.2、獲取服務編號【uuid】

本此講解的實戰中使用到的相關設備UUID

  • Service:6e40xxxx-xxxx-xxxx-e0a9-e50e24dcca9e
  • Notify:6e40xxxx-xxxx-xxxx-e0a9-e50e24dcca9e

業務邏輯梳理

權限問題,首先需要注冊藍牙相關權限;

搜索藍牙,應用啟動后可以手動的開啟和關閉藍牙掃描;

連接藍牙,根據藍牙的mac地址,調用connect進行連接;

遍歷藍牙特征,在藍牙連接成功后,獲取藍牙的服務特征,設置指定GATT特征通知;

通知數據,將數據通過藍牙服務中的通知屬性發送;

接受通知,中心設備通過characteristicChangedEvent接收通知數據,并顯示在屏幕上;

關閉藍牙,在應用推出后,需要釋放資源,斷開連接。

實戰:BLE藍牙設備間的數據交互–中心設備接收外圍設備的通知數據

一、創建項目

說明:通過DevEco Studio創建Application項目(java)。

二、權限

2.1、聲明權限

說明:在項目的config.json中聲明操作藍牙必要的權限。

  • ohos.permission.USE_BLUETOOTH:允許應用查看藍牙的配置。
  • ohos.permission.DISCOVER_BLUETOOTH:允許應用配置本地藍牙,并允許其查找遠端設備且與之配對連接。
  • ohos.permission.LOCATION:允許應用在前臺運行時獲取位置信息。

代碼如下:

 "reqPermissions": [
{
"name": "ohos.permission.USE_BLUETOOTH"
},
{
"name": "ohos.permission.DISCOVER_BLUETOOTH"
},
{
"name": "ohos.permission.LOCATION",
"reason": "$string:permreason_location",
"usedScene": {
"ability": [
".MainAbility"
],
"when": "inuse"
}
}
],

2.2、顯式聲明敏感權限

說明:ohos.permission.LOCATION屬于敏感權限,需要在代碼中顯式聲明。在MainAbility中動態申請權限,代碼如下:

 private final String PERMISSION_LOCATION = "ohos.permission.LOCATION";
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(MainAbilitySlice.class.getName());
// 判斷權限是否已授予
if (verifySelfPermission(PERMISSION_LOCATION) != IBundleManager.PERMISSION_GRANTED) {
// 應用未被授權
if (canRequestPermission(PERMISSION_LOCATION)) {
// 是否可以申請彈窗授權
requestPermissionsFromUser(new String[]{PERMISSION_LOCATION}, 0);
} else {
// 顯示應用需要權限的理由,提示用戶進入設置授權
new ToastDialog(getContext()).setText("請進入系統設置進行授權").show();
}
}
}

三、啟動藍牙

說明:如果藍牙處于關閉狀態,請求將設備的藍牙開啟,代碼如下:

BluetoothHost bluetoothHost = BluetoothHost.getDefaultHost(this);
if (bluetoothHost.getBtState() != BluetoothHost.STATE_ON) {
bluetoothHost.enableBt();
}

四、中心設備進行BLE掃描

4.1、API說明

4.1.1、BLE中心設備管理類:BleCentralManager

4.1.2、中心設備管理回調類:BleCentralManagerCallback

4.2、掃描回調的處理

BLE掃描之前要先實現掃描回調:BleCentralManagerCallback的接口,在scanResultEvent回調中可以獲取你需要的外圍設備實例,代碼如下:

BlePeripheralDevice mPeripheralDevice = null;
/**
* 實現中心設備管理回調
*/
public class MyBleCentralManagerCallback implements BleCentralManagerCallback {
/**
* 掃碼結果回調
* @param bleScanResult 掃碼結果
*/
@Override
public void scanResultEvent(BleScanResult bleScanResult) {
// 根據掃碼結果獲取外圍設備實例
mPeripheralDevice = bleScanResult.getPeripheralDevice();
}

/**
* 掃描失敗回調
* @param i
*/
@Override
public void scanFailedEvent(int i) {

}

/**
* 組掃描成功回調
* @param list 組信息
*/
@Override
public void groupScanResultsEvent(List<BleScanResult> list) {
}
}

4.3、獲取中心設備管理對象

調用BleCentralManager(BleCentralManagerCallback callback)接口獲取中心設備管理對象。代碼如下:

MyBleCentralManagerCallback myCentralManagerCallback = new MyBleCentralManagerCallback();
BleCentralManager mCentralManager = new BleCentralManager(this, myCentralManagerCallback);

4.4、啟動掃描

調用startScan()開始掃描BLE設備,在回調【BleCentralManagerCallback】中獲取掃描到的BLE設備。

值得一提的是,啟動掃描接口中,可以傳入藍牙掃描過濾器【BleScanFilter】,如果過濾器為空,則不過濾。

下面使用指定的MAC地址進行過濾啟動藍牙掃描,代碼如下:

// 開始掃描(過濾器指定的)設備
BleScanFilter bleScanFilter = new BleScanFilter();
bleScanFilter.setPeripheralAddress("E2:XX:XX:XX:XX:EB");// 替換你需要過濾的MAC
mFilters.add(bleScanFilter);
mCentralManager.startScan(mFilters);

五、藍牙連接

5.1、API

5.1.1、BLE藍牙外圍設備操作類:BlePeripheralDevice相關接口說明

5.1.2、BLE藍牙外圍設備操作回調類:BlePeripheralCallback相關接口說明

5.2、實現外圍設備操作回調:BlePeripheralCallback,部分代碼如下:

/**
* 實現外圍設備操作回調
* 中心設備作為GattService的客戶端
*/
private class MyBlePeripheralCallback extends BlePeripheralCallback {
// TODO 回調接口實現包括:connectionStateChangeEvent、servicesDiscoveredEvent、characteristicChangedEvent等
}

在回調的接口中可以做三件事。

1、在connectionStateChangeEvent回調接口中,如果GATT連接成功,則可以調用mPeripheralDevice.discoverServices()獲取外圍設備支持的 Services、Characteristics 等特征值,在回調 servicesDiscoveredEvent(int status) 中獲取外圍設備支持的服務和特征值,并根據 UUID 判斷是什么服務。代碼如下:

 /**
* 連接狀態變更
* 連接成功后可以在中心設備上(客戶端)發現GattService
* @param connectionState
*/
@Override
public void connectionStateChangeEvent(int connectionState) {
super.connectionStateChangeEvent(connectionState);
HiLog.info(label, "connectionState:" + connectionState);
if (connectionState == ProfileBase.STATE_CONNECTED && !isConnected) {
isConnected = true;
mPeripheralDevice.discoverServices();// 與外圍設備連接成功,發現GattService
setText(mTvStatus, "連接狀態:已連接");
} else if (connectionState == ProfileBase.STATE_DISCONNECTED) {
// 斷開連接
setText(mTvStatus, "連接狀態:未連接");
}
}

2、在servicesDiscoveredEvent回調接口中,如果Service獲取成功,則根據獲取到的服務和特征值,調用 setNotifyCharacteristic設置指定GATT特征通知。代碼如下:

 /**
* 在中心設備上發現服務(GattService外圍設備)的回調
* @param status 狀態
*/
@Override
public void servicesDiscoveredEvent(int status) { // 外圍設備服務發生更新觸發的回調。
if (status == BlePeripheralDevice.OPERATION_SUCC) {
HiLog.info(label, "servicesDiscoveredEvent OPERATION_SUCC");
List<GattService> services = mPeripheralDevice.getServices(); // 獲取Service成功后獲服務列表
for (GattService service : services) {
// 對每個服務進行相應操作
if (service.getUuid().equals(UUID.fromString(Constant.SERVICE_UUID))) {
HiLog.info(label, "servicesDiscoveredEvent 找到服務");
mPeripheralDevice.setNotifyCharacteristic
(service.getCharacteristic(UUID.fromString(Constant.NOTIFY_CHARACTER_UUID)).get(), true);
}
}
}
}

3、在characteristicChangedEvent回調接口中處理外圍設備特征的通知,可以從中獲取到通知的數據。代碼如下:

/**
* 特性變更的回調
* 接受外圍設備發送的數據
* @param characteristic
*/
@Override
public void characteristicChangedEvent(GattCharacteristic characteristic) {
super.characteristicChangedEvent(characteristic);
// 更新外圍設備發送的數據
String msg = new String(characteristic.getValue());
HiLog.info(label, "characteristicChangedEvent msg=" + msg);
setText(mTvData, msg);
}

5.3、設備藍牙連接

說明:中心設備與外圍設備建立連接,調用connect(boolean isAutoConnect, BlePeripheraCallback callback)建立與外圍BLE設備的GATT連接,boolean參數isAutoConnect用于設置是否允許設備在可發現距離內自動建立GATT連接。代碼如下:

MyBlePeripheralCallback mPeripheralCallback = new MyBlePeripheralCallback();
mPeripheralDevice.connect(false, mPeripheralCallback);

六、常量

說明:Constant是用于定義常量類,其中定義了業務中需要使用的常量。其中"X"需要替換成你的藍牙設備信息。

public static final String PERIPHERAL_ADDRESS = "E2:XX:XX:XX:XX:EB";// 藍牙MAC
public static final String SERVICE_UUID = "6eXXXXXX-XXXX-XXXX-XXXX-e50e24dcca9e";// 藍牙的服務編號
public static final String NOTIFY_CHARACTER_UUID = "6eXXXXXX-XXXX-XXXX-XXXX-e50e24dcca9e";// 藍牙特性通知屬性的編號

到目前為止,就完成了中心設備與外圍設備的連接和相關的監聽回調,當外圍設備通過NOTIFY_CHARACTER_UUID發送的通知在外圍設備操作回調接口characteristicChangedEvent中就能監聽到變更,在參數GattCharacteristic中就可以獲取到通知中的數據內容。

七、代碼

7.1、BLE藍牙中心設備的完整代碼

package xxx;

import com.nlscan.bluetoothassistant.ResourceTable;
import com.nlscan.bluetoothassistant.common.Constant;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.*;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.ToastDialog;
import ohos.agp.window.service.WindowManager;
import ohos.bluetooth.ProfileBase;
import ohos.bluetooth.ble.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener{
private static final HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, "BleCentralAbilitySlice");
public BlePeripheralDevice mPeripheralDevice;// 外圍設備實例
public GattCharacteristic mWriteCharacteristic;
private MyBlePeripheralCallback mPeripheralCallback;// 外圍設備操作回調
private MyBleCentralManagerCallback myCentralManagerCallback;// 中心設備管理器回調
private BleCentralManager mCentralManager;// 中心設備管理器
private List<BleScanFilter> mFilters;// 掃描過濾器
public boolean isConnected = false;// 是否已連接
private boolean isScanning = false;// 是否正在掃描
// 容器
private Text mTvStatus;// 狀態
private Text mTvData;// 數據
private Text mTvDevice;// 設備
private Button mBtnScan;// 掃描
private Button mBtnConnect;// 連接
private Button mBtnSend;// 發送
private TextField mTfInput;// 內容輸入框
private Text mTvName;// 設備名稱
private Image mIvBle;// 藍牙圖標
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
// 隱藏狀態欄、設置狀態欄和導航欄透明
getWindow().addFlags(WindowManager.LayoutConfig.MARK_FULL_SCREEN|
WindowManager.LayoutConfig.MARK_TRANSLUCENT_STATUS|
WindowManager.LayoutConfig.MARK_TRANSLUCENT_NAVIGATION);
initData();
initComponent();
initListener();
}
private void initData() {
mPeripheralCallback = new MyBlePeripheralCallback();
myCentralManagerCallback = new MyBleCentralManagerCallback();
mCentralManager = new BleCentralManager(this, myCentralManagerCallback);
mFilters = new ArrayList<>();
}

private void initComponent() {
mTvDevice = (Text) findComponentById(ResourceTable.Id_device_info);
mBtnScan = (Button) findComponentById(ResourceTable.Id_scan);
mTvStatus = (Text) findComponentById(ResourceTable.Id_status);
mBtnConnect = (Button) findComponentById(ResourceTable.Id_connect);
mTvData = (Text) findComponentById(ResourceTable.Id_data);
mBtnSend = (Button) findComponentById(ResourceTable.Id_send);
mTfInput = (TextField) findComponentById(ResourceTable.Id_input);
mTvName = (Text) findComponentById(ResourceTable.Id_device_name);
mIvBle = (Image) findComponentById(ResourceTable.Id_ble_image);
}
private void initListener() {
mBtnScan.setClickedListener(this);
mBtnConnect.setClickedListener(this);
mBtnSend.setClickedListener(this);
}
@Override
public void onClick(Component component) {
int viewId = component.getId();
if (viewId == ResourceTable.Id_scan) {
// 處理掃描
disposeScan();
} else if (viewId == ResourceTable.Id_connect) {
// 處理連接
disposeConnect();
} else if (viewId == ResourceTable.Id_send) {
// 向外圍設備發送消息
disposeSend();
}
}
/**
* 處理掃描
*/
private void disposeScan() {
if (!isScanning) {
isScanning = true;
mBtnScan.setText("停止掃描");
mTvDevice.setText("設備mac:正在掃描...");
mTvName.setText("設備名稱:暫無設備");
// 開始掃描(過濾器指定的)設備
BleScanFilter bleScanFilter = new BleScanFilter();
bleScanFilter.setPeripheralAddress(Constant.PERIPHERAL_ADDRESS);
mFilters.add(bleScanFilter);
mCentralManager.startScan(mFilters);
} else {
isScanning = false;
mBtnScan.setText("開始掃描");
// 停止掃描
mCentralManager.stopScan();
}
}
/**
* 處理連接
*/
private void disposeConnect() {
if (mPeripheralDevice == null) {
// 外圍設備對象未連接
mTvStatus.setText("連接狀態:請先掃描獲取設備信息");
return;
}
if (!isConnected) {
mBtnConnect.setText("斷開連接");
mTvStatus.setText("連接狀態:連接中...");
// 發起連接
mPeripheralDevice.connect(false, mPeripheralCallback);
} else {
isConnected = false;
mBtnConnect.setText("連接設備");
mTvStatus.setText("連接狀態:未連接");
mTvDevice.setText("設備mac:暫無設備");
mTvName.setText("設備名稱:暫無設備");
setBleImage();
// 發起斷開連接
mPeripheralDevice.disconnect();
mPeripheralDevice = null;
}
}
/**
* 處理向外圍設備發送消息
*/
private void disposeSend() {
String msg = mTfInput.getText().toString();
if (msg.isEmpty() || mPeripheralDevice == null || !isConnected) {
return;
}
// 向外圍設備發送用戶輸入的數據
mWriteCharacteristic.setValue(msg.getBytes());
boolean result = mPeripheralDevice.writeCharacteristic(mWriteCharacteristic);
HiLog.info(label, "發送內容:" + msg + "發送結果:" + result);
String sendResult = result ? "發送成功": "發送失敗";
showToast(sendResult);
}
/**
* 實現外圍設備操作回調
* 中心設備作為GattService的客戶端
*/
private class MyBlePeripheralCallback extends BlePeripheralCallback {
/**
* 在中心設備上發現服務(GattService外圍設備)的回調
* @param status 狀態
*/
@Override
public void servicesDiscoveredEvent(int status) { // 外圍設備服務發生更新觸發的回調。
if (status == BlePeripheralDevice.OPERATION_SUCC) {
HiLog.info(label, "servicesDiscoveredEvent OPERATION_SUCC");
List<GattService> services = mPeripheralDevice.getServices(); // 獲取Service成功后獲服務列表
for (GattService service : services) {
// 對每個服務進行相應操作
if (service.getUuid().equals(UUID.fromString(Constant.SERVICE_UUID))) {
HiLog.info(label, "servicesDiscoveredEvent 找到服務");
mPeripheralDevice.setNotifyCharacteristic(service.getCharacteristic(UUID.fromString(Constant.NOTIFY_CHARACTER_UUID)).get(), true);
}
}
}
}
/**
* 連接狀態變更
* 連接成功后可以在中心設備上(客戶端)發現GattService
* @param connectionState
*/
@Override
public void connectionStateChangeEvent(int connectionState) {
super.connectionStateChangeEvent(connectionState);
HiLog.info(label, "connectionState:" + connectionState);
if (connectionState == ProfileBase.STATE_CONNECTED && !isConnected) {
isConnected = true;
mPeripheralDevice.discoverServices();// 與外圍設備連接成功,發現GattService
setText(mTvStatus, "連接狀態:已連接");
} else if (connectionState == ProfileBase.STATE_DISCONNECTED) {
// 斷開連接
setText(mTvStatus, "連接狀態:未連接");
}
}
/**
* 特性變更的回調
* 接受外圍設備發送的數據
* @param characteristic
*/
@Override
public void characteristicChangedEvent(GattCharacteristic characteristic) {
super.characteristicChangedEvent(characteristic);
// 更新外圍設備發送的數據
String msg = new String(characteristic.getValue());
HiLog.info(label, "characteristicChangedEvent msg=" + msg);
setText(mTvData, msg);
}
}
/**
* 實現中心設備管理回調
*/
public class MyBleCentralManagerCallback implements BleCentralManagerCallback{
/**
* 掃碼結果回調
* @param bleScanResult 掃碼結果
*/
@Override
public void scanResultEvent(BleScanResult bleScanResult) {
// 根據掃碼結果獲取外圍設備實例
if (mPeripheralDevice == null) {
String deviceAddr = bleScanResult.getPeripheralDevice().getDeviceAddr();
String deviceName = bleScanResult.getPeripheralDevice().getDeviceName().get();
HiLog.info(label, "設備mac:" + deviceAddr);
if (Constant.PERIPHERAL_ADDRESS.equals(deviceAddr)) {
mPeripheralDevice = bleScanResult.getPeripheralDevice();
setText(mTvDevice, "設備mac:" + deviceAddr);
setText(mTvName, "設備名稱:" + deviceName);
}
}
}
/**
* 掃描失敗回調
* @param i
*/
@Override
public void scanFailedEvent(int i) {
setText(mTvDevice, "設備mac:掃描失敗,請重新掃描");
setText(mTvName, "設備名稱:暫無設備");
}
/**
* 組掃描成功回調
* @param list 組信息
*/
@Override
public void groupScanResultsEvent(List<BleScanResult> list) {
}
}
/**
* 設置Text的內容
* @param text 容器
* @param content 內容
*/
private void setText(Text text, final String content) {
getUITaskDispatcher().syncDispatch(new Runnable() {
@Override
public void run() {
text.setText(content);
}
});
}
private void showToast(String msg) {
ToastDialog toastDialog = new ToastDialog(this);
toastDialog.setAlignment(LayoutAlignment.CENTER).setText(msg).show();
}
@Override
protected void onStop() {
super.onStop();
if (mPeripheralDevice != null) {
mPeripheralDevice.disconnect();
mPeripheralDevice = null;
}
}
private void setBleImage() {
if (isConnected) {
mIvBle.setPixelMap(ResourceTable.Media_icon_ble_ling);
} else {
mIvBle.setPixelMap(ResourceTable.Media_icon_ble_black);
}
}
}

??想了解更多內容,請訪問:??

??51CTO和華為官方合作共建的鴻蒙技術社區??

??https://harmonyos.51cto.com??

責任編輯:jianghua 來源: 鴻蒙社區
相關推薦

2015-09-22 11:04:24

藍牙4.0開發

2023-03-08 21:30:33

2015-02-27 16:03:26

Android源碼Bluetooth_4BLE藍牙通信

2021-10-30 07:55:00

BLE 藍牙開發

2021-08-24 14:57:27

鴻蒙HarmonyOS應用

2023-04-17 16:10:14

鴻蒙藍牙

2024-12-24 07:38:44

C#串口通信

2022-11-17 15:26:06

低功耗藍牙鴻蒙

2018-08-03 18:15:40

物聯網通信架構IOT

2011-06-08 12:42:08

Android 藍牙

2009-09-03 17:42:07

C#開發CF藍牙模塊

2010-07-30 13:40:59

Flex開發

2013-09-12 15:37:09

iOS開發流程

2011-08-22 13:46:15

iPhone開發GameKit 藍牙

2011-08-15 10:35:43

iPhone開發Atomicnonatomic

2011-08-15 10:45:11

iPhone開發delegate

2015-06-04 10:44:59

WebAPP開發技巧

2015-06-17 10:28:10

WebAPP開發技巧

2013-04-18 10:19:40

iOS開發Xcode調試

2010-01-22 16:35:41

C++開發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人免费视频网站在线观看 | 黄色a视频 | 国产一区二区三区 | 91视频在线看| 网站黄色在线 | 亚洲精品一区国产精品 | 午夜在线视频 | 日韩中文一区二区三区 | 精品国产伦一区二区三区观看方式 | 成人av在线播放 | 成人av电影免费在线观看 | 日韩精品一区二区三区免费视频 | 在线免费看毛片 | 国产男人的天堂 | 欧美激情精品久久久久久变态 | 久久国产成人精品国产成人亚洲 | 亚洲一区在线日韩在线深爱 | 一本色道久久综合亚洲精品高清 | 中文字幕乱码一区二区三区 | av网站观看 | 中文字幕色站 | 欧产日产国产精品v | 欧美在线观看一区 | 91精品国产91久久久久游泳池 | 91久久久久久久久久久久久 | 成人免费视频网站在线看 | 午夜在线影院 | 一级免费a | 日本在线免费 | 天堂一区二区三区 | 一区二区三区欧美在线 | 啪视频在线 | 美女视频黄色的 | 精品欧美一区免费观看α√ | 亚洲综合婷婷 | 欧美综合在线视频 | 99热在线观看精品 | 精品中文字幕在线观看 | 欧美老少妇一级特黄一片 | 精品欧美一区二区在线观看 | 国产精品永久免费视频 |