移动互联网蓝牙通信(六)

编程入门 行业动态 更新时间:2024-10-11 21:26:26

移动互联网<a href=https://www.elefans.com/category/jswz/34/1768306.html style=蓝牙通信(六)"/>

移动互联网蓝牙通信(六)

移动互联网第六次项目

蓝牙通信

MainActivity.java

package android.myapplication;import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;public class MainActivity extends AppCompatActivity {public static final int MESSAGE_STATE_CHANGE = 1;public static final int MESSAGE_READ = 2;public static final int MESSAGE_WRITE = 3;public static final int MESSAGE_DEVICE_NAME = 4;public static final int MESSAGE_TOAST = 5;public static final String  DEVICE_NAME = "device_name";public static final String TOAST = "toast";public static final int REQUEST_CONNECT_DEVICE = 1;public static final int REQUEST_ENABLE_BT = 2;private ListView mConversationView;private EditText mOutEditText;private Button mSendButton;private String mConnectedDeviceName = null;private ArrayAdapter<String> mConversationArrayAdapter;private StringBuffer mOutStringBuffer;private BluetoothAdapter mBluetoothAdapter;private ChatService mChatService = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 得到本地蓝牙适配器mBluetoothAdapter=BluetoothAdapter.getDefaultAdapter();// 若当前设备不支持蓝牙功能if(mBluetoothAdapter == null){Toast.makeText(this,"蓝牙不可用",Toast.LENGTH_LONG).show();finish();return;}}@Overridepublic void onStart(){super.onStart();if(!mBluetoothAdapter.isEnabled()){// 若当前设备蓝牙功能未开启,则开启蓝牙Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableIntent,REQUEST_ENABLE_BT);} else{if(mChatService==null)setupChat();}}@Overridepublic synchronized void onResume(){super.onResume();if(mChatService != null)if(mChatService.getState() == ChatService.STATE_NONE)mChatService.start();}@Overridepublic synchronized void onPause(){super.onPause();}@Overridepublic synchronized void onStop(){super.onStop();}@Overridepublic synchronized void onDestroy(){super.onDestroy();if(mChatService != null)mChatService.stop();}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.menu_main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.switch (item.getItemId()){case R.id.scan:Intent serverIntent=new Intent(this,DeviceList.class);startActivityForResult(serverIntent,REQUEST_CONNECT_DEVICE);return true;case R.id.discoverable:ensureDiscoverable();return true;case R.id.BtOpen:if (!mBluetoothAdapter.isEnabled()) {Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(turnOn, REQUEST_ENABLE_BT);}return true;case R.id.BtOff:mBluetoothAdapter.disable();return true;}return false;}private void ensureDiscoverable(){if (mBluetoothAdapter.getScanMode() !=BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE){Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);startActivity(discoverableIntent);}}private void sendMessage(String message){if(mChatService.getState() != ChatService.STATE_CONNECTED){Toast.makeText(this,R.string.not_connected,Toast.LENGTH_SHORT).show();return;}if(message.length() > 0){byte[] send=message.getBytes();mChatService.write(send);mOutStringBuffer.setLength(0);mOutEditText.setText(mOutStringBuffer);}}private void setupChat(){mConversationArrayAdapter=new ArrayAdapter<String>(this, R.layout.list_item);mConversationView=(ListView)findViewById(R.id.list_conversation);mConversationView.setAdapter(mConversationArrayAdapter);mOutEditText=(EditText)findViewById(R.id.edit_text_out);mSendButton = (Button)findViewById(R.id.button_send);mSendButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String message = mOutEditText.getText().toString();sendMessage(message);}});mChatService = new ChatService(this,mHandler);mOutStringBuffer=new StringBuffer("");}private final Handler mHandler=new Handler(){@Overridepublic void handleMessage(Message msg){switch (msg.what){case MESSAGE_STATE_CHANGE:switch (msg.arg1){case ChatService.STATE_CONNECTED:mConversationArrayAdapter.clear();break;case ChatService.STATE_CONNECTING:break;case ChatService.STATE_LISTEN:case ChatService.STATE_NONE:break;}break;case MESSAGE_WRITE:byte[]writeBuf =(byte[])msg.obj;String writeMessage=new String(writeBuf);mConversationArrayAdapter.add("我: " + writeMessage);break;case MESSAGE_READ:byte[]readBuf =(byte[])msg.obj;String readMessage=new String(readBuf,0,msg.arg1);mConversationArrayAdapter.add(mConnectedDeviceName+": "+readMessage);break;case MESSAGE_DEVICE_NAME:mConnectedDeviceName=msg.getData().getString(DEVICE_NAME);Toast.makeText(getApplicationContext(),"链接到"+mConnectedDeviceName,Toast.LENGTH_SHORT).show();break;case MESSAGE_TOAST:Toast.makeText(getApplicationContext(),msg.getData().getString(TOAST),Toast.LENGTH_SHORT).show();break;}}};public void onActivityResult(int requesstCode, int resultCode, Intent data){switch (requesstCode){case REQUEST_CONNECT_DEVICE:if(resultCode==Activity.RESULT_OK){String address=data.getExtras().getString(DeviceList.EXTRA_DEVICE_ADDRESS);BluetoothDevice device=mBluetoothAdapter.getRemoteDevice(address);mChatService.connect(device);}break;case REQUEST_ENABLE_BT:if(resultCode == Activity.RESULT_OK){setupChat();}else {Toast.makeText(this, "bt_not_enable_leaving",Toast.LENGTH_SHORT).show();finish();}}}
}

DeviceList.java

package android.myapplication;import java.util.Set;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Toast;/*** Created by Excalibur on 2017/6/1.* 用于显示蓝牙设备列表,并返回蓝牙设备信息*/
public class DeviceList extends AppCompatActivity{public static String EXTRA_DEVICE_ADDRESS="device_address";private BluetoothAdapter mBtAdapter;private ArrayAdapter<String>mPairedDevicesArrayAdapter;private ArrayAdapter<String>mNewDevicesArrayAdapter;private IntentFilter filter = new IntentFilter();private ProgressBar progressBar;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.device_list);setResult(Activity.RESULT_CANCELED);progressBar = (ProgressBar)findViewById(R.id.processbar);Button scanButton=(Button)findViewById(R.id.button_scan);scanButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {doDiscovery();view.setVisibility(View.GONE);progressBar.setVisibility(View.VISIBLE);}});mPairedDevicesArrayAdapter=new ArrayAdapter<String>(this,R.layout.list_item);mNewDevicesArrayAdapter=new ArrayAdapter<String>(this,R.layout.list_item);ListView pairedListView=(ListView)findViewById(R.id.paired_devices);pairedListView.setAdapter(mPairedDevicesArrayAdapter);pairedListView.setOnItemClickListener(mDeviceClickListen);ListView newDeviceListView=(ListView)findViewById(R.id.new_devices);newDeviceListView.setAdapter(mNewDevicesArrayAdapter);newDeviceListView.setOnItemClickListener(mDeviceClickListen);filter.addAction(BluetoothDevice.ACTION_FOUND);filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);this.registerReceiver(mReceiver,filter);mBtAdapter=BluetoothAdapter.getDefaultAdapter();Set<BluetoothDevice>pairedDevices=mBtAdapter.getBondedDevices();if(pairedDevices.size()>0){for(BluetoothDevice device : pairedDevices){mPairedDevicesArrayAdapter.add(device.getName()+"\n"+device.getAddress());}}else{String noDevices=getResources().getText(R.string.none_paired).toString();mPairedDevicesArrayAdapter.add(noDevices);}}@Override protected void onDestroy(){super.onDestroy();if(mBtAdapter!=null){mBtAdapter.cancelDiscovery();}this.unregisterReceiver(mReceiver);}private void doDiscovery(){if(mBtAdapter.isDiscovering())mBtAdapter.cancelDiscovery();mBtAdapter.startDiscovery();}private OnItemClickListener mDeviceClickListen=new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView,View view, int i, long l) {mBtAdapter.cancelDiscovery();String info=((TextView) view).getText().toString();String address=info.substring(info.length()-17);Intent intent =new Intent();intent.putExtra(EXTRA_DEVICE_ADDRESS,address);setResult(Activity.RESULT_OK,intent);finish();}};private final BroadcastReceiver mReceiver = new BroadcastReceiver() {@Override public void onReceive(Context context, Intent intent) {String action=intent.getAction();if(BluetoothDevice.ACTION_FOUND.equals(action)){BluetoothDevice  device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if(device.getBondState() != BluetoothDevice.BOND_BONDED){mNewDevicesArrayAdapter.add(device.getName()+"\n" +device.getAddress());}}else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){progressBar.setVisibility(View.GONE);Toast.makeText(DeviceList.this,"搜索完毕",Toast.LENGTH_SHORT).show();if(mNewDevicesArrayAdapter.getCount()==0){String noDevices=getResources().getText(R.string.none_found).toString();mNewDevicesArrayAdapter.add(noDevices);}}}};
}

ChatService.java

package android.myapplication;

/**

  • Created by Excalibur on 2017/5/30.
    */

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

public class ChatService {
private static final String NAME=“MainActivity”;

// UUID-->通用唯一识别码,能唯一地辨识咨询
private static final UUID MY_UUID=UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");//串口// "fa87c0d0-afac-11de-8a39-0800200c9a66");private final BluetoothAdapter mAdapter;
private final Handler mHandler ;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;public static final int STATE_NONE = 0;
public static final int STATE_LISTEN = 1;
public static final int STATE_CONNECTING = 2;
public static final int STATE_CONNECTED = 3;public ChatService(Context context, Handler handler){mAdapter=BluetoothAdapter.getDefaultAdapter();mState = STATE_NONE;mHandler = handler;
}private synchronized void setState(int state){mState = state;mHandler.obtainMessage(MainActivity.MESSAGE_STATE_CHANGE,state,-1).sendToTarget();
}public synchronized int getState(){return mState;
}public synchronized void start(){if(mConnectThread !=null){mConnectThread.cancel();mConnectThread=null;}if(mConnectedThread !=null){mConnectedThread.cancel();mConnectedThread=null;}if (mAcceptThread==null){mAcceptThread=new AcceptThread();mAcceptThread.start();}setState(STATE_LISTEN);
}// 取消 Connecting Connected状态下的相关线程,然后运行新的mConnectThread线程
public synchronized void connect(BluetoothDevice device){if(mState == STATE_CONNECTED){if(mConnectThread !=null){mConnectThread.cancel();mConnectThread=null;}}if(mConnectedThread !=null) {mConnectedThread.cancel();mConnectedThread = null;}if(mAcceptThread != null){mAcceptThread.cancel();mAcceptThread =null;}mConnectThread = new ConnectThread(device);mConnectThread.start();setState(STATE_CONNECTING);
}// 开启一个ConnectThread来管理对应的当前连接。之前取消任意现存的mConnectThread
// mConnectThread,mAcceptThread线程,然后开启新的mConnectThread,传入当前
// 刚刚接受的socket连接,最后通过Handler来通知UI连接
public synchronized void connected(BluetoothSocket socket,BluetoothDevice device){if(mConnectThread !=null){mConnectThread.cancel();mConnectThread=null;}if(mConnectedThread !=null){mConnectedThread.cancel();mConnectedThread=null;}if(mAcceptThread !=null){mAcceptThread.cancel();mAcceptThread=null;}mConnectedThread=new ConnectedThread(socket);mConnectedThread.start();Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_DEVICE_NAME);Bundle bundle = new Bundle();bundle.putString(MainActivity.DEVICE_NAME,device.getName());msg.setData(bundle);mHandler.sendMessage(msg);setState(STATE_CONNECTED);
}// 停止所有相关线程,设当前状态为none
public synchronized void stop(){if(mConnectThread !=null){mConnectThread.cancel();mConnectThread=null;}if(mConnectedThread !=null){mConnectedThread.cancel();mConnectedThread=null;}if(mAcceptThread !=null){mAcceptThread.cancel();mAcceptThread=null;}setState(STATE_NONE);
}// 在STATE_CONNECTED状态下,调用mConnectedThread里的write方法,写入byte
public void write(byte[]out){ConnectedThread r;synchronized (this){if(mState != STATE_CONNECTED)return;r = mConnectedThread;}r.write(out);
}// 连接失败的时候处理,通知UI,并设为STATE_LISTEN状态
private void connectionFailed(){setState(STATE_LISTEN);Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);Bundle bundle=new Bundle();bundle.putString(MainActivity.TOAST,"链接不到设备");msg.setData(bundle);mHandler.sendMessage(msg);ChatService.this.start();
}// 当连接失去的时候,设为STATE_LISTEN
private void connectionLost(){setState(STATE_LISTEN);Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);Bundle bundle=new Bundle();bundle.putString(MainActivity.TOAST,"设备链接中断");msg.setData(bundle);mHandler.sendMessage(msg);ChatService.this.start();
}// 创建监听线程,准备接受新连接。使用阻塞方式,调用BluetoothServerSocket.accept()
private class AcceptThread extends Thread{private final BluetoothServerSocket mmServerSocket;public AcceptThread(){BluetoothServerSocket tmp = null;try{tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME,MY_UUID);}catch (IOException e){}mmServerSocket = tmp;}public void run(){BluetoothSocket socket= null;while(mState != STATE_CONNECTED){try{socket = mmServerSocket.accept();}catch (IOException e) {break;}if(socket != null){connected(socket,socket.getRemoteDevice());try{mmServerSocket.close();}catch (IOException e){}}}
}public void cancel(){try{mmServerSocket.close();}catch (IOException e){}}

}

// 连接线程,专门用来对外发出连接对方蓝牙的请求并进行处理
// 构造函数里通过BluetoothDevice.createRfcommSocketToServiceRecord(),
// 从待连接的device产生BluetoothSocket,然后在run方法中connect
// 成功后调用 BluetoothChatService的connnected()方法,定义cancel()在关闭线程时能关闭socket
private class ConnectThread extends Thread{private final BluetoothSocket mmSocket;private final BluetoothDevice mmDevice;public ConnectThread(BluetoothDevice device){// Use a temporary object that is later assigned to mmSocket,// because mmSocket is finalmmDevice=device;BluetoothSocket tmp = null;// Get a BluetoothSocket to connect with the given BluetoothDevicetry{// MY_UUID is the app's UUID string, also used by the server codetmp = device.createRfcommSocketToServiceRecord(MY_UUID);}catch (IOException e){}mmSocket = tmp;}public void run(){// Cancel discovery because it will slow down the connectionmAdapter.cancelDiscovery();try{// Connect the device through the socket. This will block// until it succeeds or throws an exceptionmmSocket.connect();}catch (IOException e){connectionFailed();// Unable to connect; close the socket and get outtry{mmSocket.close();}catch (IOException e2){}//ChatService.this.start();return;}synchronized(ChatService.this){mConnectedThread = null;}connected(mmSocket,mmDevice);}public void cancel(){/* try{mmSocket.close();}catch (IOException e){}*/}
}// 双方蓝牙连接后一直运行的线程。构造函数中设置输入输出流。
// Run方法中使用阻塞模式的InputStream.read()循环读取输入流
// 然后psot到UI线程中更新聊天信息。也提供了write()将聊天消息写入输出流传输至对方,
// 传输成功后回写入UI线程。最后cancel()关闭连接的socketprivate class ConnectedThread extends Thread{private final BluetoothSocket mmSocket;private final InputStream mmInStream;private final OutputStream mmOutStream;public ConnectedThread(BluetoothSocket socket){mmSocket = socket;InputStream tmpIn = null;OutputStream tmpOut=null;// Get the input and output streams, using temp objects because// member streams are finaltry{tmpIn=mmSocket.getInputStream();tmpOut=mmSocket.getOutputStream();}catch (IOException e){}mmInStream = tmpIn;mmOutStream = tmpOut;}public void run(){byte[]buffer=new byte[1024];int bytes;while (true){try{bytes = mmInStream.read(buffer);mHandler.obtainMessage(MainActivity.MESSAGE_READ,bytes,-1,buffer).sendToTarget();}catch (IOException e){connectionLost();break;}}}public void write(byte[]buffer){try{mmOutStream.write(buffer);}catch (IOException e){Log.d("MainActivity","Send Fail");}mHandler.obtainMessage(MainActivity.MESSAGE_WRITE,buffer).sendToTarget();}public void cancel(){try{mmSocket.close();}catch (IOException e){}}
}

}

Layout布局

1.activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android=""xmlns:app=""xmlns:tools=""android:layout_width="match_parent"android:layout_height="match_parent"android:background="@mipmap/wallpaper1"tools:context="android.myapplication.MainActivity"><ListViewandroid:id="@+id/list_conversation"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="8dp"app:layout_constraintBottom_toTopOf="@+id/re_layout"></ListView><RelativeLayoutandroid:id="@+id/re_layout"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"><EditTextandroid:id="@+id/edit_text_out"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/edit_hint"android:inputType="text" /><Buttonandroid:id="@+id/button_send"android:layout_alignParentRight="true"android:layout_alignParentEnd="true"android:layout_width="48dp"android:layout_height="wrap_content"android:background="@mipmap/enter_48px" /></RelativeLayout></android.support.constraint.ConstraintLayout>

2.device_list.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android=""android:layout_width="match_parent"android:layout_height="match_parent"android:background="@mipmap/wallpaper1"><LinearLayoutandroid:id="@+id/llayout1"android:orientation="horizontal"android:layout_alignParentTop="true"android:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:layout_width="0dp"android:layout_weight="1"android:layout_height="wrap_content"android:textAlignment="center"android:textColor="@color/white"android:textSize="18sp"android:text="@string/pairedDevice"/><TextViewandroid:layout_width="0dp"android:layout_weight="1"android:textAlignment="center"android:textColor="@color/white"android:layout_height="wrap_content"android:textSize="18sp"android:text="@string/foundDevice"/></LinearLayout><LinearLayoutandroid:layout_below="@id/llayout1"android:layout_above="@id/button_scan"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"><ListViewandroid:id="@+id/paired_devices"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"></ListView><ListViewandroid:id="@+id/new_devices"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"></ListView></LinearLayout><Buttonandroid:id="@+id/button_scan"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:background="@drawable/bord"android:text="@string/scan" /><ProgressBarandroid:id="@+id/processbar"android:layout_width="wrap_content"android:layout_height="wrap_content"android:visibility="gone"android:layout_centerHorizontal="true"android:layout_alignParentBottom="true" />
</RelativeLayout>

3.list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android=""android:layout_width="match_parent"android:layout_height="wrap_content"android:textColor="@color/white"android:padding="10dp"android:textSize="16sp">
</TextView>

menu布局

1.添加menu目录


2.添加menu_main.xml

<menu xmlns:android=""xmlns:app=""xmlns:tools=""tools:context="android.myapplication.MainActivity" ><itemandroid:id="@+id/scan"android:title="@string/scan"/><itemandroid:id="@+id/discoverable"android:title="@string/device_visibility"/><itemandroid:id="@+id/BtOpen"android:title="@string/bluetoothON"/><itemandroid:id="@+id/BtOff"android:title="@string/bluetoothOff"/>
</menu>

注意1.AndroidManifest.xml中添加

<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission><uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>

注意2.res/value/strings.xml布局添加

<string name="not_connected">你没有链接一个设备</string><string name="bt_not_enabled_leaving">蓝牙不可用,离开聊天室</string><string name="title_connecting">链接中...</string><string name="title_connected_to">连接到:</string><string name="title_not_connected">无链接</string><string name="scanning">蓝牙设备搜索中...</string><string name="select_device">选择一个好友链接</string><string name="none_paired">没有配对好友</string><string name="none_found">附近没有发现好友</string><string name="title_paired_devices">已配对好友</string><string name="title_other_devices">其它可连接好友</string><string name="button_scan">搜索好友</string><string name="connect">我的好友</string><string name="discoverable">设置在线</string><string name="back">退出</string><string name="startVideo">开始聊天</string><string name="stopVideo">结束聊天</string>

更多推荐

移动互联网蓝牙通信(六)

本文发布于:2024-02-05 10:37:40,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1744622.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:蓝牙   互联网   通信

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!