|
利用wifi实现android手机远程遥控
发表于 2014-10-8 16:44:04
浏览:25714
|
回复:10
打印
只看该作者
[复制链接]
楼主
本帖最后由 lynn3653 于 2014-10-10 16:06 编辑
当前诸多电视盒都提供了手机端的远程遥控软件,如乐视的多屏看看等,那如果我们拥有一部android手机和一块android开发板(或者电视盒),我们也可轻松开发出一款远程遥控软件,因为主要的技术点仅仅以下两点而已:
1)Client端(android手机)Socket广播搜寻Server端(android开发板),获取Server端IP地址;
Client端使用socket 7777(端口号自行选用,不冲突即可)广播"is_remoteService ?"
- socket_7777 = new DatagramSocket(7777);
- Log.v("tag", "socket_7777");
- InetAddress serverAddress = InetAddress.getByName("255.255.255.255");
- String str = "is_remoteService ?";
- byte data [] = str.getBytes(); //把传输内容分解成字节
- DatagramPacket packet = new DatagramPacket(data, data.length, serverAddress, 7777);
- //调用socket对象的send方法,发送数据
- socket_7777.send(packet);
复制代码
进入循环等待Server端回复,获取Server端IP地址
- //创建一个空的DatagramPacket对象
- //DatagramPacket packet_re = new DatagramPacket(data,data.length);
- //使用receive方法接收客户端所发送的数据,
- //如果客户端没有发送数据,该进程就停滞在这里
- while(true)
- {
- DatagramPacket packet_re = new DatagramPacket(data,data.length);
- try {
- socket_7777.setSoTimeout(3000);
- Log.e("TAG", ">>>receive_packet_begin");
- socket_7777.receive(packet_re);
- Log.e("TAG", ">>>receive_packet_end");
- String result = new String(packet_re.getData(),packet_re.getOffset(),packet_re.getLength());
- Log.v("TAG", "result--->" + result);
- String address = packet_re.getAddress().getHostAddress().toString();
- Log.v("TAG", "address--->" + address);
- if(result.indexOf("is_remoteService") == -1 && "is_remoteService".indexOf(result) == -1)
- {
- list.add(result);
- listAddress.add(address);
- }
- } catch (IOException e) {
- e.printStackTrace();
- break;
- }
- }
复制代码
Server端使用socket 7777接收"is_remoteService ?",然后获取IP地址并回复mDeviceName给Client端
- byte[] buffer = new byte[64];
- try {
- mListenerSocket = new DatagramSocket(7777);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- Log.e(TAG, "new DatagramSocket(7777) err!");
- return;
- }
- while(mFlag){
- try {
- DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
- mListenerSocket.receive(packet);
- InetAddress address = packet.getAddress();
- System.out.println(address.getHostAddress() + " "+new String(packet.getData()));
- String revStr = new String(packet.getData());
- if(revStr.indexOf("is_remoteService ?")==0){
- mDeviceName = android.os.Build.MODEL;
- packet = new DatagramPacket(mDeviceName.getBytes(), 0, mDeviceName.getBytes().length, address, packet.getPort());
- mListenerSocket.send(packet);
- }else{
- Log.e(TAG, "not is remoteServiec ! err!");
- }
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
复制代码
2)将Client端的虚拟按键事件转化成简单字符串用socket发送至Sever端,Server端解析字符串获得按键事件,并使用injectInputEvent方法向android上层上报按键事件;
Client 发起端口号9999的TCP连接
- socket_9999 = new Socket(serverAddress_s, 9999);//serverAddress_s为第一步Server端回复中取得
- try {
- m9999Out = new PrintWriter(socket_9999.getOutputStream(), true);
- } catch (IOException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
复制代码
连接成功后即可使用m9999Out发送命令字符串
- m9999Out.println(cmd_string);
复制代码
Server端用端口号9999 accept TCP连接
- try {
- mWifiServerSocket = new ServerSocket(9999, 3);
- } catch (IOException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- while(mFlag){
- try {
- Socket client = mWifiServerSocket.accept();
- Remote newRemote = new Remote(client); //每接收到一个TCP连接都建立一个Remote节点单独处理
- mRemotes.add(newRemote);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- private class Remote{
- private Object mSocket;
- private BufferedReader mIn = null;
- private PrintWriter mOut = null;
- private boolean mFlag = true;
- Remote(Object socket){
- mSocket = socket;
- try {
- mIn = new BufferedReader(new InputStreamReader(((Socket)mSocket).getInputStream()));
- mOut = new PrintWriter(new OutputStreamWriter(((Socket)mSocket).getOutputStream()), true);
- } catch (IOException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
-
- ReadThread thread = new ReadThread(Remote.this, mIn, mOut);
- thread.start();
- }
- public void release(){
- mFlag = false;
- try {
- mIn.close();
- mOut.close();
- ((Socket)mSocket).close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
复制代码
ReadThread中使用mIn阻塞接收Client端的命令字符串并解析
- while(mFlag)
- {
- try {
- String mrecvStr = mIn.readLine();
- Log.d(TAG, "read: "+mrecvStr);
- if(mrecvStr == null || mrecvStr == "null"){
- Log.w(TAG, "null is received!");
- mRemoteNode.release();
- mRemotes.remove(mRemoteNode);
- break;
- }
- String[] mstrs = mrecvStr.split("\n");
- int i = 0;
- while( i < mstrs.length)
- {
- recvStr = mstrs<i>;
- </i> i++;
- if (i >= 2)
- {
- Log.d(TAG, "Multicommand send in one time!");
- }
- if(recvStr.equalsIgnoreCase("online")){
- String str = "online";
- mOut.println(str);
- }else{
- String[] strs = recvStr.split(" ",5);
- if(strs.length <= 1){
- Log.e(TAG,"error cmd!");
- continue;
- }
-
- if( strs[0].equalsIgnoreCase("key")) {
- int keyCode = Integer.parseInt(strs[1]);
- VKey.sendKeyEventToAndroid(keyCode);
- Log.d(TAG, "new sendKeyEvent keyCode:"+keyCode);
- }else{
- Log.w(TAG,"Unknow Command:"+recvStr);
- }
- }
- }
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- mRemoteNode.release();
- mRemotes.remove(mRemoteNode);
- return;
- }
- }
复制代码
将解析的指令转成KeyEvent 注入系统即完成整个遥控流程!
- public class VKey {
- public static boolean sendKeyEventToAndroid(int userKey) {
- Log.d(TAG, "sendKeyEventToAndroid() start");
- boolean result = false;
- if (userKey != -1) {
- //TODO: 以下代码必须依存系统源码编译
- final KeyEvent evd = new KeyEvent(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, userKey, 0,
- 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
- InputDevice.SOURCE_KEYBOARD);
- final KeyEvent evu = new KeyEvent(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, userKey, 0,
- 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
- InputDevice.SOURCE_KEYBOARD);
- InputManager.getInstance().injectInputEvent(evd,
- InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
- InputManager.getInstance().injectInputEvent(evu,
- InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
- // mIWindowManager.injectKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, key), false);
- // mIWindowManager.injectKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, key), false);
- result = true;
- }
- Log.d(TAG, "sendKeyEventToAndroid() end");
- return result;
- }
复制代码
笔者用三星的GT-I9308手机实际效果如下图:
当扫描到设备列表如笔者的firefly开发板"rk3288"后,点击“rk3288”即会有“已链接设备*.*.*.*”提示,然后点击“左”“右”按钮即可看到开发板有相应的响应!
附源码!
|
|