Android 手机遥控器控制机顶盒(电视)

来源:互联网 发布:乾隆身世 知乎 编辑:程序博客网 时间:2024/04/29 01:05

公司需求: 参考悟空遥控器做下手机控制机顶盒的功能,手机端apk界面参考遥控器,机顶盒apk在设置里面加个开关,打开的时候运行个后台server,手机端发送数据机顶盒的server接收到后处理相关动作。

需求出来了怎么实现呢?首先应用程序的通信无非就是Socket与Http,其中Socket又可以用TCP和UDP,HTTP的话就衍生出很多方式,基础的HTTP GET和POST请求,然后就是WebService的SOAP。

在这些方式中,Socket当然是最基础的。因此先从Socket开始。
首先是服务器端:打开服务器,等待客户端链接并接收消息即KeyCode,响应相应事件;
然后是客户端:模拟遥控器的UI界面,搭好界面,为每个控件添加点击事件并赋值相应KeyCode,连接服务器,将KeyCode信息传递给服务器端。
完成之后需要在资源配置文件中添加网络权限:

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

所有完成之后,测试时发现响应按键时只能在当前应用内使用,当离开此应用界面时,会报无权限异常,这时需要在Manifest.xml中添加
最高权限:

android:sharedUserId="android.uid.system"

这时需要在SDK下使用mk文件编译:
Android.mk

ifneq ($(BOARD_USE_DEFAULT_APPINSTALL),false)LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := $(call all-subdir-java-files)LOCAL_PACKAGE_NAME := RemoteTVLOCAL_CERTIFICATE := platforminclude $(BUILD_PACKAGE)endif

整个思路就是这样,下面上代码:

ClientActivity,这里用到了StrictMode(严苛模式),不懂的可以百度了解了解,在这里我只做了数字键和上下左右键的模拟,有需要的可以自己添加:

public class ClientActivity extends Activity implements OnClickListener {    private EditText mServerIp;    private EditText mServerPort;    private EventSender mEventSender;    @Override    protected void onCreate(Bundle savedInstanceState) {        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()                .detectDiskReads()                .detectDiskWrites()                .detectNetwork()                 .penaltyLog()                 .build());        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()                .detectLeakedSqlLiteObjects()                 .penaltyLog()                 .penaltyDeath()                .build());        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_client);        mServerIp = (EditText) findViewById(R.id.cli_adr_edi);        mServerPort = (EditText) findViewById(R.id.cli_port_edi);        findViewById(R.id.cli_connect_btn).setOnClickListener(this);findViewById(R.id.num_1).setOnClickListener(this);findViewById(R.id.num_2).setOnClickListener(this);findViewById(R.id.num_3).setOnClickListener(this);findViewById(R.id.num_4).setOnClickListener(this);findViewById(R.id.num_5).setOnClickListener(this);findViewById(R.id.num_6).setOnClickListener(this);findViewById(R.id.num_7).setOnClickListener(this);findViewById(R.id.num_8).setOnClickListener(this);findViewById(R.id.num_9).setOnClickListener(this);findViewById(R.id.btn_up).setOnClickListener(this);findViewById(R.id.btn_left).setOnClickListener(this);findViewById(R.id.btn_right).setOnClickListener(this);findViewById(R.id.btn_down).setOnClickListener(this);}    @Override    public void onClick(View v) {        int code = -1;        switch (v.getId()) {            case R.id.cli_connect_btn:                if(mEventSender != null) mEventSender.close();                mEventSender = new EventSender(mServerIp.getText().toString(), Integer.valueOf(mServerPort.getText().toString()));                mEventSender.connect();                return;            case R.id.num_1:             code = KeyEvent.KEYCODE_1;                break;            case R.id.num_2:                code = KeyEvent.KEYCODE_2;                break;            case R.id.num_3:                code = KeyEvent.KEYCODE_3;                break;            case R.id.num_4:                code = KeyEvent.KEYCODE_4;                break;            case R.id.num_5:                code = KeyEvent.KEYCODE_5;                break;            case R.id.num_6:                 code = KeyEvent.KEYCODE_6;                break;            case R.id.num_7:                code = KeyEvent.KEYCODE_7;                break;            case R.id.num_8:                code = KeyEvent.KEYCODE_8;                break;            case R.id.num_9:                code = KeyEvent.KEYCODE_9;                break;            case R.id.btn_up:                code=KeyEvent.KEYCODE_DPAD_UP;                break;              case R.id.btn_left:                code=KeyEvent.KEYCODE_DPAD_LEFT;                break;            case R.id.btn_down:                code=KeyEvent.KEYCODE_DPAD_DOWN;                break;            case R.id.btn_right:                code=KeyEvent.KEYCODE_DPAD_RIGHT;                break;        }           if(mEventSender == null) return;        mEventSender.println(createKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, code)));    }    private String createKeyEvent(KeyEvent event) {        JSONObject json = new JSONObject();        try {            json.put("Event", event.getKeyCode());        } catch (JSONException e) {            e.printStackTrace();        }        return json.toString();    }    public class EventSender {        private static final String TAG = "EventSender";        private Socket mSocket;        private String mDstAddress;        private int mDstPort;        private PrintWriter mPrintWriter;        private EventSender(String dstAddress, int dstPort){            Log.d(TAG, "EventSender");            mDstAddress = dstAddress;            mDstPort = dstPort;            mSocket = new Socket();        }         public void println(String str){            mPrintWriter.println(str);        }        public boolean close(){            Log.d(TAG, "close()");            if(mSocket != null){                try {                    mSocket.close();                    mSocket = null;                    return true;                } catch (IOException e) {                    e.printStackTrace();                }            }            return false;        }        public boolean connect(){            Log.d(TAG, "connect()");            try {                if (mSocket != null && !mSocket.isConnected()) {                    Log.d(TAG, "new InetSocketAddress()");                    mSocket.connect(new InetSocketAddress(mDstAddress, mDstPort));                    mPrintWriter = new PrintWriter(mSocket.getOutputStream(), true);                    mSocket.setKeepAlive(true);                }                return true;                 }catch (IOException e) {                e.printStackTrace();            }            return false;        }    }}

服务器端:

public class ServerActivity extends Activity implements OnClickListener{    private static final String TAG = "ServerActivity";    private RemoteServer mRemoteServer;    private EditText mServerPort;    private TextView mServerRecEvent;    private int keycode;    private Instrumentation instrumentation;    @Override    protected void onCreate(Bundle savedInstanceState) {    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()                .detectDiskReads()                .detectDiskWrites()                .detectNetwork()                 .penaltyLog()                 .build());        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()                .detectLeakedSqlLiteObjects()                 .penaltyLog()                .penaltyDeath()                .build());        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_server);        findViewById(R.id.ser_port_btn).setOnClickListener(this);        mServerPort = (EditText) findViewById(R.id.ser_port_edi);        mServerRecEvent = (TextView) findViewById(R.id.ser_recev_event);    }    @Override    public void onClick(View v) {        openServer(Integer.valueOf(mServerPort.getText().toString()));    }    public void openServer(int dstPort){        Log.d(TAG, "openServer() - dstPort:" + dstPort);        mServerRecEvent.setText("");        if (mRemoteServer == null) {            mRemoteServer = new RemoteServer(dstPort);            if(mRemoteServer.openServer()) {                mServerRecEvent.setText("服务启动成功!!!!/r/n");            }             Log.d(TAG, "openServer() - mRemoteServer:" + mRemoteServer);        }    }    private void onEvent(String line) {        Log.d(TAG, "line: " + line);        try {            JSONObject object=new JSONObject(line);            keycode = (int) object.get("Event");            Log.d(TAG, "keycode: " + keycode);            if (instrumentation==null){                instrumentation=new Instrumentation();            }            //通过KeyCode响应相应操作            instrumentation.sendKeyDownUpSync(keycode);            Log.d(TAG, "event key : " + keycode);        } catch (JSONException e) {   e.printStackTrace();        }        Message msg = Message.obtain();        msg.what = 0;        msg.obj = line;        mHandler.sendMessage(msg);   }    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            String text = mServerRecEvent.getText().toString();            mServerRecEvent.setText(text + String.valueOf(msg.obj));        }    };    class RemoteServer implements Runnable{        private static final String TAG = "RemoteServer";        private int mPort;        private ServerSocket mServerSocket;        private boolean mIsClose = false;     public boolean isClose(){            return mIsClose;        }        public boolean close(){            try {                mServerSocket.close();                mServerSocket = null;                mIsClose = true;            } catch (IOException e) {                e.printStackTrace();            }            return mIsClose;        }        public RemoteServer(int port){            Log.d(TAG, "RemoteServer()");            mPort = port;        }        public boolean openServer(){            try {                mServerSocket = new ServerSocket(mPort);                new Thread(this).start();                return true;            } catch (IOException e) {                e.printStackTrace();            }            return false;        }        public void run() {            try {                while (!mIsClose) {                    Socket socket = mServerSocket.accept();                    new ServerThread(socket);                }            } catch (IOException e) {            }        }        private class ServerThread extends Thread {            private Socket client;            private BufferedReader in;            public ServerThread(Socket s) throws IOException {                client = s;                in = new BufferedReader(new InputStreamReader(client.getInputStream()));                start();            }            public void run() {                android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);                try {                    String line = in.readLine();                    while (!mIsClose) {                        if(line != null){                            onEvent(line);                        }                        line = in.readLine();                    }                    Log.d(TAG, "--- See you, bye! ---");                 client.close();                }                catch (IOException e) {                    e.printStackTrace();                }            }        }    }}

MainActivity

public class MainActivity extends Activity implements View.OnClickListener {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        findViewById(R.id.btn_client).setOnClickListener(this);        findViewById(R.id.btn_server).setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.btn_client:             startActivity(new Intent(this, ClientActivity.class));                break;            case R.id.btn_server:                startActivity(new Intent(this, ServerActivity.class));                break;        }    }}

布局就不放了,有需要的可以看下实现过程,主要就是Socket通信,下面上界面,界面时测试界面,很丑,凑合着看吧:
首先在客户端和盒子上安装编译好的APP,在盒子端进入服务器端,输入端口号:img-w10
在手机端进入客户端,输入服务器端的IP地址和端口号:
img-w150
注意这里,连接成功时没有做判断,点击连接服务后,如果没反应即连接成功了。
还有:盒子和手机一定要在同一个局域网下!!!客户端输入的端口号和服务器输入的端口号一定要一致。

代码下载地址:http://download.csdn.net/download/json_jerry/9955125
本来想0积分提供,不知道为什么最低需要1积分。