首页 » 技术分享 » Android 手机遥控器控制机顶盒(电视)

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

 

公司需求: 参考悟空遥控器做下手机控制机顶盒的功能,手机端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 := optional

LOCAL_SRC_FILES := $(call all-subdir-java-files)

LOCAL_PACKAGE_NAME := RemoteTV
LOCAL_CERTIFICATE := platform

include $(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积分。

转载自原文链接, 如需删除请联系管理员。

原文链接:Android 手机遥控器控制机顶盒(电视),转载请注明来源!

0