Saturday, May 25, 2013

Android remote control Java source code, client


This code is from project: Raspberry pi and android simple remote control

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.ctrl"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="10"
        android:targetSdkVersion="10" />
  <uses-permission android:name="android.permission.INTERNET"> </uses-permission>
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"> </uses-permission>
  <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.ctrl.Control_1"
            android:label="Home Control" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

control_1.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:background="@drawable/background"
    tools:context=".Control_1">

    <ToggleButton
        android:id="@+id/tb_1"
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:layout_alignParentLeft="true"
        android:textOn="ON"
        android:textOff="OFF"
        android:layout_alignParentTop="true"/>

    <ToggleButton
        android:id="@+id/tb_2"
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:layout_alignLeft="@+id/tb_1"
        android:layout_below="@+id/tb_1"
        android:textOn="ON"
        android:textOff="OFF"
        android:layout_marginTop="22dp"/>

    <ToggleButton
        android:id="@+id/tb_3"
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:layout_alignLeft="@+id/tb_2"
        android:layout_below="@+id/tb_2"
        android:textOn="ON"
        android:textOff="OFF"
        android:layout_marginTop="22dp"/>

    <ToggleButton
        android:id="@+id/tb_4"
        android:layout_width="100dp"
        android:layout_height="60dp"
        android:layout_alignLeft="@+id/tb_3"
        android:layout_below="@+id/tb_3"
        android:textOn="ON"
        android:textOff="OFF"
        android:layout_marginTop="22dp"/>

    <TextView
        android:id="@+id/tv_Status"
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:layout_alignLeft="@+id/tb_4"
        android:layout_below="@+id/tb_4"
        android:layout_marginTop="20dp"
        android:textColor="#ffffff"
        android:shadowColor="#ff0000"/>

    <TextView
        android:id="@+id/tv_B1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/tb_1"
        android:layout_alignBottom="@+id/tb_1"
        android:layout_marginLeft="22dp"
        android:layout_toRightOf="@+id/tb_1"
        android:singleLine="true"
        android:textColor="#ffffff"
        android:textAppearance="?android:attr/textAppearanceMedium"/>

    <TextView
        android:id="@+id/tv_B2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/tb_2"
        android:layout_alignBottom="@+id/tb_2"
        android:layout_alignLeft="@+id/tv_B1"
        android:singleLine="true"
        android:textColor="#ffffff"
        android:textAppearance="?android:attr/textAppearanceMedium"/>

    <TextView
        android:id="@+id/tv_B3"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/tb_3"
        android:layout_alignBottom="@+id/tb_3"
        android:layout_alignLeft="@+id/tv_B2"
        android:singleLine="true"
        android:textColor="#ffffff"
        android:textAppearance="?android:attr/textAppearanceMedium"/>

    <TextView
        android:id="@+id/tv_B4"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/tb_4"
        android:layout_alignBottom="@+id/tb_4"
        android:layout_alignLeft="@+id/tv_B3"
        android:singleLine="true"
        android:textColor="#ffffff"   
        android:textAppearance="?android:attr/textAppearanceMedium"/>

</RelativeLayout>

dimens.xml

<resources>

    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>

</resources>

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Ctrl</string>

</resources>

styles.xml

<resources>

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="android:Theme.Light">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.
        -->
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
    </style>

</resources>

CommandManager.java

package com.example.ctrl;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;

import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;



// Main class
public class CommandManager {
   
   private String serverIpAddress = null; 
   private int    serverPort      = 0;
   
   private String responceString = null;     // here will be answer from 
                                             // raspberry
   
   private int    readWaitSecTime = 0;       // wait for reply from raspberry
   private int    error           = 0;       // status of communication
   

   // getter, setter
   public String getServerIpAddress() {
      return serverIpAddress;
   }


   public void setServerIpAddress(String serverIpAddress) {
      this.serverIpAddress = serverIpAddress;
   }


   public void setServerPort(int serverPort) {
      this.serverPort = serverPort;
   }


   public int getError() {
      return error;
   }


   public int setReadWaitSecTime(int readWaitSecTime) {
      int prev = this.readWaitSecTime;
      
      this.readWaitSecTime = readWaitSecTime;      
      return prev;
   }


   public String getResponceString() {
      return responceString;
   }
  


   // This method sends command to other side of the wire and
   // fetch response. If there was any error, then 'error' variable
   // is set.

   // When send -> recv will success, function returns 'true' if not,
   // 'false'.

   public boolean execute(String command) {
      
      InetAddress serverAddr              = null;
      Socket         serverSocket         = null;
      InputStream    serverInputStream    = null;
      OutputStream   serverOutputStream   = null;
      boolean        readOk               = false;
      
      InetSocketAddress inetAddr          = null;

      this.error           = 0;
      this.responceString  = null;
                  
      try {

         serverAddr  = InetAddress.getByName(serverIpAddress);
         inetAddr    = new InetSocketAddress(serverAddr, serverPort);

      } catch (UnknownHostException e1) {

         this.error = -3;
         return readOk;

      }  
      
      try {

         serverSocket = new Socket();
         serverSocket.connect(inetAddr, 100);

      } catch (IOException e) {

         this.error = -1;
         return readOk;

      }
      
      try {

         if (serverSocket.isConnected() == true) {                               

            serverInputStream  = serverSocket.getInputStream();
            serverOutputStream = serverSocket.getOutputStream();
         
            command+="\r\n";
            serverOutputStream.write(command.getBytes());   
     
            // loop pools input stream for data 
            for(int i = 0; i < readWaitSecTime * 50; i++) {

               // weak, but working
               int bytesToRead = serverInputStream.available();
               
               if ( bytesToRead != 0) {
                  
                  byte[] bytes = new byte[30];
                     
                  serverInputStream.read(bytes,0, bytesToRead);

                  this.responceString = new String(bytes,0, bytesToRead );
                                    
                  readOk = true;
                  break;
               }

               Thread.sleep(10);
            }
         
            if (readOk == false)
               this.error = -2;

            serverInputStream.close();
            serverOutputStream.close();

            } else {
               this.error = -1;
            }
               
         serverSocket.close();

      } catch (IOException e) {

         this.error = -4;
         return readOk;    

      } catch (InterruptedException e) {

         this.error = -5;
         return readOk;

      }
      
      return readOk;
   }


}

Control_1.java

package com.example.ctrl;

import java.util.ArrayList;

import android.os.Bundle;
import android.app.Activity;
import android.app.KeyguardManager;
import android.app.KeyguardManager.KeyguardLock;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGestureListener;
import android.support.v4.view.GestureDetectorCompat;

import android.view.GestureDetector;
import android.view.MotionEvent;


import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.ToggleButton;

// Main class 
public class Control_1 extends Activity implements OnCheckedChangeListener {

   private GestureDetectorCompat mDetector; 

   // arrays for buttons and thier descriptions
   ArrayList<ToggleButton> buttons     = new ArrayList<ToggleButton>();
   ArrayList<TextView>     buttonsText = new ArrayList<TextView>();
   
   TextView       tvStatus;

   final int      WAIT_SHORT     = 1;
   final int      WAIT_LONG      = 4;
   
   int            screenNum      = 0; 
   boolean        screenChange   = false;
   
   KeyguardManager   keyguardManager   = null;
   KeyguardLock      lock              = null; ;
   
   // create new object to communicate with raspberry
   CommandManager cm = new CommandManager();
  
 

   // This method refreshes button prefixes, descriptions and states 
   // Once we've make a gesture (left, right), screen prefix was changed
   // and button prefixes, description and states needs to be updated.

   private void refreshButtons(int screenNum) {

      short i;
     
      // update new screen number 
      this.setTitle("Control " + screenNum);
      
      // set all buttons to OFF
      for (ToggleButton b : buttons)
         b.setChecked(false);    
      
      // clear all buttons descriptions
      for (TextView t : buttonsText)
         t.setText("");
      
      // check if is worth to fetch descriptions and staes.
      if( !cm.execute("GET PING CONN") ) {
         showError();
         return;
      }
  

      // send, recv. and set names for buttons with
      // new prefixes 
      i = 1;
      for (TextView t : buttonsText)
          if( cm.execute("GET NAME B" + (4*screenNum + i++)) )
            t.setText(cm.getResponceString());
    
      
      // send, recv. and set states for buttons with
      // new prefixes 
      i = 1;
      for (ToggleButton b : buttons)
          if( cm.execute("GET STATE B" + (4*screenNum + i++ )) )
            b.setChecked( cm.getResponceString().contains("ON"));

      // show last error
      showError();
   }
   
   
   @Override
   protected void onPause() {
      // when app goes into pause, reenable screen lock
      lock.reenableKeyguard();
      super.onPause();
   }
   

   @Override
   protected void onResume() {

      // refresh button desc. , names and states
      screenChange = true; // this will prevent to fire
                           // OnCheckedChangeListener logic

      refreshButtons(screenNum);
      screenChange = false;

      // disable screen lock
      lock.disableKeyguard();

      super.onResume();
   }

   
   @Override
   protected void onDestroy() {
      // when app goes off, reenable screen lock
      lock.reenableKeyguard();
      super.onDestroy();      
   }
   
   
   @Override
   public void finish() {
      // when app goes off, reenable screen lock
      lock.reenableKeyguard();
      super.finish();
   }
   

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      
      setContentView(R.layout.control_1);
             
      keyguardManager   = (KeyguardManager)getSystemService(Activity.KEYGUARD_SERVICE);
      lock              = keyguardManager.newKeyguardLock(KEYGUARD_SERVICE);
      
      lock.disableKeyguard();

      mDetector = new GestureDetectorCompat(this, new MyGestureListener());
      
      cm.setServerIpAddress("192.168.1.104");
      cm.setServerPort(8000);
      
      cm.setReadWaitSecTime(WAIT_SHORT);
      
      buttons.add( (ToggleButton) findViewById(R.id.tb_1) );
      buttons.add( (ToggleButton) findViewById(R.id.tb_2) );
      buttons.add( (ToggleButton) findViewById(R.id.tb_3) );
      buttons.add( (ToggleButton) findViewById(R.id.tb_4) );

      // add listener      
       for (ToggleButton b : buttons)
          b.setOnCheckedChangeListener(this);
      
      tvStatus = (TextView)    findViewById(R.id.tv_Status);
      
      buttonsText.add( (TextView) findViewById(R.id.tv_B1) );
      buttonsText.add( (TextView) findViewById(R.id.tv_B2) );
      buttonsText.add( (TextView) findViewById(R.id.tv_B3) );
      buttonsText.add( (TextView) findViewById(R.id.tv_B4) );
      
      setStatus("empty");
   }


   @Override 
   public boolean onTouchEvent(MotionEvent event){ 
     this.mDetector.onTouchEvent(event);
     return super.onTouchEvent(event);
   }


   class MyGestureListener extends GestureDetector.SimpleOnGestureListener implements OnGestureListener {

      @Override
      public boolean onFling(MotionEvent arg0, MotionEvent arg1,
            float arg2, float arg3) {

         // slide from right to left on screen
         if ((arg0.getX() - arg1.getX()) > 0 ) {
            
            // slide on upper 1/5 of screen will jump by 5 screens
            if(arg0.getY() < 110)
               screenNum+=5;           
            else  // slide on 4/5 of screen will jump by 1 screen
               screenNum++;

            screenChange = true; // prevent onChecked... logic
            refreshButtons(screenNum);
            screenChange = false;
         }
         
         // slide from left to right
         if ((arg1.getX() - arg0.getX()) > 0 ) {
            
            if(arg0.getY() < 110)
               screenNum-=5;           
            else
               screenNum--;            
            
            if (screenNum < 0) {
               screenNum = 0;
            }
            screenChange = true;
            refreshButtons(screenNum); 
            screenChange = false;
         }
         
         return false; 
      }

 
      public  boolean onDoubleTap(MotionEvent e) {
         // on double tap, refresh current screen
         screenChange = true;
         refreshButtons(screenNum);
         screenChange = false;
         return false;
      }

      
      public  void onLongPress(MotionEvent e) {
         screenNum = 0;
         screenChange = true;
         refreshButtons(screenNum);
         screenChange = false;
      }


      @Override
      public void onGesture(GestureOverlayView arg0, MotionEvent arg1) {}


      @Override
      public void onGestureCancelled(GestureOverlayView arg0, MotionEvent arg1) {}

      
      @Override
      public void onGestureEnded(GestureOverlayView arg0, MotionEvent arg1) {}


      @Override
      public void onGestureStarted(GestureOverlayView arg0, MotionEvent arg1) {}
   }


   @Override
   public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
     
      // do nothing when screen is changed 
      if (screenChange == true ) {
         return;
      }
      
      String bName = "";
      
      // fetch prefix of changed button
      switch(buttonView.getId()) {     
         case  R.id.tb_1: { bName = "B"+(4*screenNum + 1 ); } break;    
         case  R.id.tb_2: { bName = "B"+(4*screenNum + 2 ); } break;       
         case  R.id.tb_3: { bName = "B"+(4*screenNum + 3 ); } break;       
         case  R.id.tb_4: { bName = "B"+(4*screenNum + 4 ); } break;
      }  

      int prev = cm.setReadWaitSecTime(WAIT_SHORT);
      
      // send new state, recv. respnoce and set new button status
      if( cm.execute("SET STATE " + bName + " " + isChecked) ) {
         buttonView.setChecked( cm.getResponceString().contains("ON"));       
      } else {
         showError();
         buttonView.setChecked(false);
      }

      cm.setReadWaitSecTime(prev);
   }
   

   public void setStatus(String status) {       
      tvStatus.setText("Status: " +status);
   }
   

   public boolean showError() {
      if(cm.getError() == 0) {
         setStatus("ok");
         return false;
      }
               
      switch(cm.getError()) {
         case -1: setStatus("Server not reached"); break;            
         case -2: setStatus("Read timeout"); break;         
         case -3: setStatus("Unknown host"); break;         
         case -4: setStatus("Interrupted");break;
      };
      
      return true;
   }


}

7 comments:

  1. this code shows error , network on main thread !!

    ReplyDelete
    Replies
    1. Code has no error. Look again, it's NOT connected all time to the server, it only connects when command need to be executed, execute() method: connects, send command, get response and disconnects. In this case there is no sense to put networking stuff in separate thread.

      Delete
    2. My app is crashing, can you help me with this?

      Delete
    3. This app is crashing can you help me?

      Delete
  2. is the need server in pc for this app and what type of server can i use?please help i have already created on app like this but its not working kindly help me

    ReplyDelete
  3. i need my own remote control app as my project i am student please help

    ReplyDelete
  4. Please help with us in my PC Control using Android Based Keyboard and Mouse, I am A Student of VU in Pakistan,My contact is fiaz.ahmad7611@gmail.com

    ReplyDelete