Showing posts with label Android code sample: Networking. Show all posts
Showing posts with label Android code sample: Networking. Show all posts

Sunday, June 4, 2017

Scan Devices IP connected in WiFi network


Example to scan connected devices within the same WiFi network, using InetAddress.isReachable().


package com.blogspot.android_er.androidwireless;

import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    TextView tvWifiState;
    TextView tvScanning, tvResult;

    ArrayList<InetAddress> inetAddresses;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvWifiState = (TextView)findViewById(R.id.WifiState);
        tvScanning = (TextView)findViewById(R.id.Scanning);
        tvResult = (TextView)findViewById(R.id.Result);

        //To prevent memory leaks on devices prior to Android N,
        //retrieve WifiManager with
        //getApplicationContext().getSystemService(Context.WIFI_SERVICE),
        //instead of getSystemService(Context.WIFI_SERVICE)
        WifiManager wifiManager =
                (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        tvWifiState.setText(readtvWifiState(wifiManager));

        new ScanTask(tvScanning, tvResult).execute();
    }

    // "android.permission.ACCESS_WIFI_STATE" is needed
    private String readtvWifiState(WifiManager wm){
        String result = "";
        switch (wm.getWifiState()){
            case WifiManager.WIFI_STATE_DISABLED:
                result = "WIFI_STATE_DISABLED";
                break;
            case WifiManager.WIFI_STATE_DISABLING:
                result = "WIFI_STATE_DISABLING";
                break;
            case WifiManager.WIFI_STATE_ENABLED:
                result = "WIFI_STATE_ENABLED";
                break;
            case WifiManager.WIFI_STATE_ENABLING:
                result = "WIFI_STATE_ENABLING";
                break;
            case WifiManager.WIFI_STATE_UNKNOWN:
                result = "WIFI_STATE_UNKNOWN";
                break;
            default:
        }
        return result;
    }

    private class ScanTask extends AsyncTask<Void, String, Void> {

        TextView tvCurrentScanning, tvScanResullt;
        ArrayList<String> canonicalHostNames;

        public ScanTask(TextView tvCurrentScanning, TextView tvScanResullt) {
            this.tvCurrentScanning = tvCurrentScanning;
            this.tvScanResullt = tvScanResullt;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            tvCurrentScanning.setText("Finished.");
            tvScanResullt.setText("");
            for(int i = 0; i < inetAddresses.size(); i++){
                tvScanResullt.append(canonicalHostNames.get(i) + "\n");
            }
        }

        @Override
        protected Void doInBackground(Void... voids) {
            scanInetAddresses();
            return null;
        }

        @Override
        protected void onProgressUpdate(String... values) {
            tvCurrentScanning.setText(values[0]);
        }

        private void scanInetAddresses(){
            //May be you have to adjust the timeout
            final int timeout = 500;

            if(inetAddresses == null){
                inetAddresses = new ArrayList<>();
            }
            inetAddresses.clear();

            if(canonicalHostNames == null){
                canonicalHostNames = new ArrayList<>();
            }
            canonicalHostNames.clear();

            //For demonstration, scan 192.168.1.xxx only
            byte[] ip = {(byte) 192, (byte) 168, (byte) 1, 0};
            for (int j = 0; j < 255; j++) {
                ip[3] = (byte) j;
                try {
                    InetAddress checkAddress = InetAddress.getByAddress(ip);
                    publishProgress(checkAddress.getCanonicalHostName());
                    if (checkAddress.isReachable(timeout)) {
                        inetAddresses.add(checkAddress);
                        canonicalHostNames.add(checkAddress.getCanonicalHostName());
                    }
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                    publishProgress(e.getMessage());
                } catch (IOException e) {
                    e.printStackTrace();
                    publishProgress(e.getMessage());
                }
            }
        }
    }
}


<LinearLayout 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:orientation="vertical"
    tools:context="com.blogspot.android_er.androidwireless.MainActivity" >

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/WifiState"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Scanning: "/>
        <TextView
            android:id="@+id/Scanning"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textStyle="italic"/>
    </LinearLayout>

    <TextView
        android:id="@+id/Result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"/>

</LinearLayout>


uses-permission of "android.permission.ACCESS_WIFI_STATE" and "android.permission.INTERNET" are needed.

Saturday, June 3, 2017

Get ssid of connected network and my IP address

Android example code to get ssid and IP address, using WifiInfo.

Tested on Samsung Galaxy A9, running Android 6.0.1.

Wifi enabled and connected

Wifi disabled

MainActivity.java
package com.blogspot.android_er.androidwireless;

import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.format.Formatter;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    TextView tvWifiEnabled, tvWifiState, tvWifiInfo, tvSSID,
                tvRssi, tvIP, tvFormattedIP1, tvFormattedIP2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvWifiEnabled = (TextView)findViewById(R.id.WifiEnabled);
        tvWifiState = (TextView)findViewById(R.id.WifiState);
        tvWifiInfo = (TextView)findViewById(R.id.WifiInfo);
        tvSSID = (TextView)findViewById(R.id.SSID);
        tvRssi = (TextView)findViewById(R.id.Rssi);
        tvIP = (TextView)findViewById(R.id.IP);
        tvFormattedIP1 = (TextView)findViewById(R.id.FormattedIP1);
        tvFormattedIP2 = (TextView)findViewById(R.id.FormattedIP2);

        //To prevent memory leaks on devices prior to Android N,
        //retrieve WifiManager with
        //getApplicationContext().getSystemService(Context.WIFI_SERVICE),
        //instead of getSystemService(Context.WIFI_SERVICE)
        WifiManager wifiManager =
                (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        tvWifiEnabled.setText("isWifiEnabled(): " + wifiManager.isWifiEnabled());
        tvWifiState.setText(readtvWifiState(wifiManager));

        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        if(wifiInfo == null){
            tvWifiInfo.setText("wifiInfo == null !!!");
        }else{
            tvWifiInfo.setText(wifiInfo.toString());
            tvSSID.setText("SSID: " + wifiInfo.getSSID());
            tvRssi.setText("Rssi: " + wifiInfo.getRssi() + " dBm");

            int ipAddress = wifiInfo.getIpAddress();
            /*
            Formatter.formatIpAddress() was deprecated in API level 12.
            This method does not support IPv6 addresses.
             */
            String FormatedIpAddress = Formatter.formatIpAddress(ipAddress);
            String FormatedIpAddress2 = String.format("%d.%d.%d.%d",
                    (ipAddress & 0xff),
                    (ipAddress >> 8 & 0xff),
                    (ipAddress >> 16 & 0xff),
                    (ipAddress >> 24 & 0xff));
            tvIP.setText("IP: " + wifiInfo.getIpAddress());
            tvFormattedIP1.setText("" + FormatedIpAddress);
            tvFormattedIP2.setText("" + FormatedIpAddress2);
        }

    }

    // "android.permission.ACCESS_WIFI_STATE" is needed
    private String readtvWifiState(WifiManager wm){
        String result = "";
        switch (wm.getWifiState()){
            case WifiManager.WIFI_STATE_DISABLED:
                result = "WIFI_STATE_DISABLED";
                break;
            case WifiManager.WIFI_STATE_DISABLING:
                result = "WIFI_STATE_DISABLING";
                break;
            case WifiManager.WIFI_STATE_ENABLED:
                result = "WIFI_STATE_ENABLED";
                break;
            case WifiManager.WIFI_STATE_ENABLING:
                result = "WIFI_STATE_ENABLING";
                break;
            case WifiManager.WIFI_STATE_UNKNOWN:
                result = "WIFI_STATE_UNKNOWN";
                break;
            default:
        }
        return result;
    }
}


layout
<LinearLayout 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:orientation="vertical"
    tools:context="com.blogspot.android_er.androidwireless.MainActivity" >

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <TextView
        android:id="@+id/WifiEnabled"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/WifiState"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/WifiInfo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="italic"/>
    <TextView
        android:id="@+id/SSID"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:textColor="#FF0000"/>
    <TextView
        android:id="@+id/Rssi"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="#00FF00"/>
    <TextView
        android:id="@+id/comment1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:text="get IP Address:"/>
    <TextView
        android:id="@+id/IP"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="italic"
        android:textColor="#0000FF"/>
    <TextView
        android:id="@+id/FormattedIP1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="italic"
        android:textColor="#0000FF"/>
    <TextView
        android:id="@+id/FormattedIP2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="italic"
        android:textColor="#0000FF"/>

</LinearLayout>


uses-permission of "android.permission.ACCESS_WIFI_STATE" is needed in AndroidManifest.xml.

Remark on MAC:
Please take a look on the captured screen; the MAC address is 02:00:00:00:00:00.

Refer to Android 6.0 Changes - Access to Hardware Identifier:
To provide users with greater data protection, starting in this release, Android removes programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs. The WifiInfo.getMacAddress() and the BluetoothAdapter.getAddress() methods now return a constant value of 02:00:00:00:00:00.

Wednesday, June 1, 2016

Android Datagram/UDP Server example


I posted "Java Datagram/UDP Server and Client, run on raspberry Pi" on my another blogspot. And last post show "Android Datagram/UDP Client example". This post show a Datagram/UDP Server run on Android.


MainActivity.java
package com.blogspot.android_er.androidudpserver;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Date;
import java.util.Enumeration;

public class MainActivity extends AppCompatActivity {

    private final static String TAG = MainActivity.class.getSimpleName();

    TextView infoIp, infoPort;
    TextView textViewState, textViewPrompt;

    static final int UdpServerPORT = 4445;
    UdpServerThread udpServerThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        infoIp = (TextView) findViewById(R.id.infoip);
        infoPort = (TextView) findViewById(R.id.infoport);
        textViewState = (TextView)findViewById(R.id.state);
        textViewPrompt = (TextView)findViewById(R.id.prompt);

        infoIp.setText(getIpAddress());
        infoPort.setText(String.valueOf(UdpServerPORT));
    }

    @Override
    protected void onStart() {
        udpServerThread = new UdpServerThread(UdpServerPORT);
        udpServerThread.start();
        super.onStart();
    }

    @Override
    protected void onStop() {
        if(udpServerThread != null){
            udpServerThread.setRunning(false);
            udpServerThread = null;
        }

        super.onStop();
    }

    private void updateState(final String state){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                textViewState.setText(state);
            }
        });
    }

    private void updatePrompt(final String prompt){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                textViewPrompt.append(prompt);
            }
        });
    }

    private class UdpServerThread extends Thread{

        int serverPort;
        DatagramSocket socket;

        boolean running;

        public UdpServerThread(int serverPort) {
            super();
            this.serverPort = serverPort;
        }

        public void setRunning(boolean running){
            this.running = running;
        }

        @Override
        public void run() {

            running = true;

            try {
                updateState("Starting UDP Server");
                socket = new DatagramSocket(serverPort);

                updateState("UDP Server is running");
                Log.e(TAG, "UDP Server is running");

                while(running){
                    byte[] buf = new byte[256];

                    // receive request
                    DatagramPacket packet = new DatagramPacket(buf, buf.length);
                    socket.receive(packet);     //this code block the program flow

                    // send the response to the client at "address" and "port"
                    InetAddress address = packet.getAddress();
                    int port = packet.getPort();

                    updatePrompt("Request from: " + address + ":" + port + "\n");

                    String dString = new Date().toString() + "\n"
                            + "Your address " + address.toString() + ":" + String.valueOf(port);
                    buf = dString.getBytes();
                    packet = new DatagramPacket(buf, buf.length, address, port);
                    socket.send(packet);

                }

                Log.e(TAG, "UDP Server ended");

            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(socket != null){
                    socket.close();
                    Log.e(TAG, "socket.close()");
                }
            }
        }
    }

    private String getIpAddress() {
        String ip = "";
        try {
            Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
                    .getNetworkInterfaces();
            while (enumNetworkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = enumNetworkInterfaces
                        .nextElement();
                Enumeration<InetAddress> enumInetAddress = networkInterface
                        .getInetAddresses();
                while (enumInetAddress.hasMoreElements()) {
                    InetAddress inetAddress = enumInetAddress.nextElement();

                    if (inetAddress.isSiteLocalAddress()) {
                        ip += "SiteLocalAddress: "
                                + inetAddress.getHostAddress() + "\n";
                    }

                }

            }

        } catch (SocketException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            ip += "Something Wrong! " + e.toString() + "\n";
        }

        return ip;
    }
}


activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:padding="16dp"
    android:orientation="vertical"
    tools:context="com.blogspot.android_er.androidudpserver.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/infoip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textStyle="italic" />

    <TextView
        android:id="@+id/infoport"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textStyle="italic" />

    <TextView
        android:id="@+id/state"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="un-initiated"
        android:textSize="20dp"/>

    <TextView
        android:id="@+id/prompt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18dp"/>
</LinearLayout>


uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml

Remark about life-cycle:
In this example, the DatagramSocket server is run in background thread. I haven't handle the life-cycle very well (Actually I don't think any application will have UI like this example). Consider the cases:

Case One:
- Start the app, the activity display on screen and the DatagramSocket opened in associated thread.
- the code socket.receive(packet) block the program flow, so the thread stay here and waiting data request.
- Exit the app. It will set running to false, to request the thread to stop. But the thread is blocked in socket.receive(packet), so it's still running.
- Restart the app, the new thread cannot open the DatagramSocket, because it's still held by old thread.
- Client send a request, the DatagramSocket server response the request and exit socket.receive(packet), and check running and exit.
- In this case, the current activity and associated thread have no DatagramSocket opened!

Case Two:
- Start the app, the activity display on screen and the DatagramSocket opened in associated thread.
- the code socket.receive(packet) block the program flow, so the thread stay here and waiting data request.
- Exit the app. It will set running to false, to request the thread to stop. But the thread is blocked in socket.receive(packet), so it's still running.
- Client send a request, the DatagramSocket server response the request and exit socket.receive(packet), and check running and exit.
- Restart the app, and open the DatagramSocket.
- In this case, the current activity and associated thread can open DatagramSocket and work as expected.


download filesDownload the files .

Sunday, May 29, 2016

Android client example 2, communicate with Java Server run on Raspberry Pi


Refer to the previous Android client example to send message to Java server on Raspberry Pi. The client Android Client connect To Java Server, and send something then close socket. This example show how Android Client connect to Java Server (run on raspberry Pi) and keep connected, and send to and receive from Server.


For the Server side, it's Java Echo Server to send back the received data to the sender.

Please notice:
Suppose the Disconnect button is used to disconnect from server once clicked. In this example, it cannot actually. Because the code bufferedReader.readLine() in ClientThread.java will block the program. The Disconnect request will wait until anything received to return from bufferedReader.readLine().

Create ClientThread.java to handle network related job in background thread.
package com.blogspot.android_er.androidclient;

import android.os.Message;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

public class ClientThread extends Thread{

    String dstAddress;
    int dstPort;
    private boolean running;
    MainActivity.ClientHandler handler;

    Socket socket;
    PrintWriter printWriter;
    BufferedReader bufferedReader;

    public ClientThread(String addr, int port, MainActivity.ClientHandler handler) {
        super();
        dstAddress = addr;
        dstPort = port;
        this.handler = handler;
    }

    public void setRunning(boolean running){
        this.running = running;
    }

    private void sendState(String state){
        handler.sendMessage(
                Message.obtain(handler,
                        MainActivity.ClientHandler.UPDATE_STATE, state));
    }

    public void txMsg(String msgToSend){
        if(printWriter != null){
            printWriter.println(msgToSend);
        }
    }

    @Override
    public void run() {
        sendState("connecting...");

        running = true;

        try {
            socket = new Socket(dstAddress, dstPort);
            sendState("connected");

            OutputStream outputStream = socket.getOutputStream();
            printWriter = new PrintWriter(outputStream, true);

            InputStream inputStream = socket.getInputStream();
            InputStreamReader inputStreamReader =
                    new InputStreamReader(inputStream);
            bufferedReader = new BufferedReader(inputStreamReader);

            while(running){

                //bufferedReader block the code
                String line = bufferedReader.readLine();
                if(line != null){
                    handler.sendMessage(
                            Message.obtain(handler,
                                    MainActivity.ClientHandler.UPDATE_MSG, line));
                }

            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(bufferedReader != null){
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(printWriter != null){
                printWriter.close();
            }

            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        handler.sendEmptyMessage(MainActivity.ClientHandler.UPDATE_END);
    }
}


MainActivity.java
package com.blogspot.android_er.androidclient;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    EditText editTextAddress, editTextPort, editTextMsg;
    Button buttonConnect, buttonDisconnect, buttonSend;
    TextView textViewState, textViewRx;

    ClientHandler clientHandler;
    ClientThread clientThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editTextAddress = (EditText) findViewById(R.id.address);
        editTextPort = (EditText) findViewById(R.id.port);
        editTextMsg = (EditText) findViewById(R.id.msgtosend);
        buttonConnect = (Button) findViewById(R.id.connect);
        buttonDisconnect = (Button) findViewById(R.id.disconnect);
        buttonSend = (Button)findViewById(R.id.send);
        textViewState = (TextView)findViewById(R.id.state);
        textViewRx = (TextView)findViewById(R.id.received);

        buttonDisconnect.setEnabled(false);
        buttonSend.setEnabled(false);

        buttonConnect.setOnClickListener(buttonConnectOnClickListener);
        buttonDisconnect.setOnClickListener(buttonDisConnectOnClickListener);
        buttonSend.setOnClickListener(buttonSendOnClickListener);

        clientHandler = new ClientHandler(this);
    }

    View.OnClickListener buttonConnectOnClickListener =
            new View.OnClickListener() {

                @Override
                public void onClick(View arg0) {

                    clientThread = new ClientThread(
                            editTextAddress.getText().toString(),
                            Integer.parseInt(editTextPort.getText().toString()),
                            clientHandler);
                    clientThread.start();

                    buttonConnect.setEnabled(false);
                    buttonDisconnect.setEnabled(true);
                    buttonSend.setEnabled(true);
                }
            };

    View.OnClickListener buttonDisConnectOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(clientThread != null){
                clientThread.setRunning(false);
            }

        }
    };

    View.OnClickListener buttonSendOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(clientThread != null){
                String msgToSend = editTextMsg.getText().toString();
                clientThread.txMsg(msgToSend);
            }
        }
    };

    private void updateState(String state){
        textViewState.setText(state);
    }

    private void updateRxMsg(String rxmsg){
        textViewRx.append(rxmsg + "\n");
    }

    private void clientEnd(){
        clientThread = null;
        textViewState.setText("clientEnd()");
        buttonConnect.setEnabled(true);
        buttonDisconnect.setEnabled(false);
        buttonSend.setEnabled(false);

    }

    public static class ClientHandler extends Handler {
        public static final int UPDATE_STATE = 0;
        public static final int UPDATE_MSG = 1;
        public static final int UPDATE_END = 2;
        private MainActivity parent;

        public ClientHandler(MainActivity parent) {
            super();
            this.parent = parent;
        }

        @Override
        public void handleMessage(Message msg) {

            switch (msg.what){
                case UPDATE_STATE:
                    parent.updateState((String)msg.obj);
                    break;
                case UPDATE_MSG:
                    parent.updateRxMsg((String)msg.obj);
                    break;
                case UPDATE_END:
                    parent.clientEnd();
                    break;
                default:
                    super.handleMessage(msg);
            }

        }

    }
}


activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:padding="16dp"
    android:orientation="vertical"
    tools:context="com.blogspot.android_er.androidclient.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <EditText
        android:id="@+id/address"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="192.168."
        android:hint="dstAddress" />
    <EditText
        android:id="@+id/port"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="8000"
        android:hint="dstPort" />
    <Button
        android:id="@+id/connect"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Connect"/>
    <Button
        android:id="@+id/disconnect"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Disconnect"/>
    <TextView
        android:id="@+id/state"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="un-initiated"
        android:textSize="20dp"/>
    <EditText
        android:id="@+id/msgtosend"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="msg to send..." />
    <Button
        android:id="@+id/send"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send"/>
    <TextView
        android:id="@+id/received"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18dp"/>
</LinearLayout>


uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml


download filesDownload the files .

Monday, May 23, 2016

Android client to send message to Java server on Raspberry Pi


It's a Java client and server exercise in my another blogspot HelloraspberryPi. The client connect to server and send something, the server simple print the received message and close.

It's Android version of the client, to connect to server and send something.


MainActivity.java
package com.blogspot.android_er.androidclient;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class MainActivity extends AppCompatActivity {

    EditText editTextAddress, editTextPort, editTextMsg;
    Button buttonConnect;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editTextAddress = (EditText) findViewById(R.id.address);
        editTextPort = (EditText) findViewById(R.id.port);
        editTextMsg = (EditText) findViewById(R.id.msgtosend);
        buttonConnect = (Button) findViewById(R.id.connect);

        buttonConnect.setOnClickListener(buttonConnectOnClickListener);
    }

    View.OnClickListener buttonConnectOnClickListener =
            new View.OnClickListener() {

                @Override
                public void onClick(View arg0) {
                    MyClientTask myClientTask = new MyClientTask(
                            editTextAddress.getText().toString(),
                            Integer.parseInt(editTextPort.getText().toString()));
                    myClientTask.execute(editTextMsg.getText().toString());
                }
            };

    public class MyClientTask extends AsyncTask<String, Void, Void> {

        String dstAddress;
        int dstPort;
        String response;

        MyClientTask(String addr, int port) {
            dstAddress = addr;
            dstPort = port;
        }

        @Override
        protected Void doInBackground(String... params) {
            try {
                Socket socket = new Socket(dstAddress, dstPort);

                OutputStream outputStream = socket.getOutputStream();
                PrintStream printStream = new PrintStream(outputStream);
                printStream.print(params[0]);

                socket.close();

            } catch (UnknownHostException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }

    }
}


layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:padding="16dp"
    android:orientation="vertical"
    tools:context="com.blogspot.android_er.androidclient.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <EditText
        android:id="@+id/address"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="dstAddress" />
    <EditText
        android:id="@+id/port"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="dstPort" />
    <EditText
        android:id="@+id/msgtosend"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="msg to send..." />
    <Button
        android:id="@+id/connect"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Connect and send..."/>

</LinearLayout>


uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml

The Java code of the server side, refer to "Java Network exercise: client and server - client send something to server".

The next example "Android client example 2, communicate with Java Server run on Raspberry Pi" show how Android Client connect to Java Server (run on raspberry Pi) and keep connected, and send to and receive from Server.

Monday, December 21, 2015

Get HostName of WiFi hotspot clients, and check if it is still connected.


Previous posts show how to "Retrieve IP and MAC addresses from /proc/net/arp" and "Lookup manufacturer/vendor info from MAC address". This post show how to get the Host Name of the connected clients.

It can be noted that if we call getCanonicalHostName() or getHostName() methods of the InetAddressobjects, it will return  the IP address. If we call getLocalHost().getCanonicalHostName() or getLocalHost().getHostName() methods, it will return the host name, "localhost".

Also, if a devices disconnected, the file /proc/net/arp will not updated immediately. We can determine if it is still connected by calling inetAddress.isReachable(timeout). If false returned, means it is disconnected.

MainActivity.java
package com.blogspot.android_er.androidlistclient;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    Button btnRead;
    TextView textResult;

    ListView listViewNode;
    ArrayList<Node> listNote;
    ArrayAdapter<Node> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnRead = (Button)findViewById(R.id.readclient);
        textResult = (TextView)findViewById(R.id.result);

        listViewNode = (ListView)findViewById(R.id.nodelist);
        listNote = new ArrayList<>();
        ArrayAdapter<Node> adapter =
                new ArrayAdapter<Node>(
                        MainActivity.this,
                        android.R.layout.simple_list_item_1,
                        listNote);
        listViewNode.setAdapter(adapter);

        btnRead.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new TaskReadAddresses(listNote, listViewNode).execute();
            }
        });
    }

    class Node {
        String ip;
        String mac;
        String CanonicalHostName;
        String HostName;
        String LocalHostCanonicalHostName;
        String LocalHostHostName;
        String remark;
        boolean isReachable;

        Node(String ip, String mac){
            this.ip = ip;
            this.mac = mac;
            queryHost();
        }

        @Override
        public String toString() {
            return "IP: " + ip + "\n" +
                    "MAC: " + mac + "\n" +
                    "CanonicalHostName:\t" + CanonicalHostName + "\n" +
                    "HostName:\t" + HostName + "\n" +
                    "getLocalHost().getCanonicalHostName():\t" + LocalHostCanonicalHostName + "\n" +
                    "getLocalHost().getHostName():\t" + LocalHostHostName + "\n" +
                    "isReachable: " + isReachable +
                    "\n" + remark;
        }

        private void queryHost(){
            try {
                InetAddress inetAddress = InetAddress.getByName(ip);
                CanonicalHostName = inetAddress.getCanonicalHostName();
                HostName = inetAddress.getHostName();
                LocalHostCanonicalHostName = inetAddress.getLocalHost().getCanonicalHostName();
                LocalHostHostName = inetAddress.getLocalHost().getHostName();
                isReachable = inetAddress.isReachable(3000);

            } catch (UnknownHostException e) {
                e.printStackTrace();
                remark = e.getMessage();
            } catch (IOException e) {
                e.printStackTrace();
                remark = e.getMessage();
            }
        }
    }

    private class TaskReadAddresses extends AsyncTask<Void, Node, Void> {

        ArrayList<Node> array;
        ListView listView;

        TaskReadAddresses(ArrayList<Node> array, ListView v){
            listView = v;
            this.array = array;
            array.clear();
            textResult.setText("querying...");
        }

        @Override
        protected Void doInBackground(Void... params) {
            readAddresses();
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            textResult.setText("Done");
        }

        @Override
        protected void onProgressUpdate(Node... values) {
            listNote.add(values[0]);
            ((ArrayAdapter)(listView.getAdapter())).notifyDataSetChanged();
        }

        private void readAddresses() {
            BufferedReader bufferedReader = null;

            try {
                bufferedReader = new BufferedReader(new FileReader("/proc/net/arp"));

                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    String[] splitted = line.split(" +");
                    if (splitted != null && splitted.length >= 4) {
                        String ip = splitted[0];
                        String mac = splitted[3];
                        if (mac.matches("..:..:..:..:..:..")) {
                            Node thisNode = new Node(ip, mac);
                            publishProgress(thisNode);
                        }
                    }
                }

            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally{
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}



Sunday, December 20, 2015

Lookup manufacturer info by MAC address, using www.macvendorlookup.com API

Last post show how to "Retrieve IP and MAC addresses of Android WiFi tethering clients from /proc/net/arp". This example show how to get vendor/manufacturer info of the associated MAC addresses.

(You can download runnable APK from link on bottom)


http://www.macvendorlookup.com/api provide API to lookup MAC Address Vendor/Manufacturer info.

Notice that this example haven't handle error condition.


MainActivity.java
package com.blogspot.android_er.androidlistclient;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    Button btnRead;
    TextView textResult;

    ListView listViewNode;
    ArrayList<Node> listNote;
    ArrayAdapter<Node> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnRead = (Button)findViewById(R.id.readclient);
        textResult = (TextView)findViewById(R.id.result);

        listViewNode = (ListView)findViewById(R.id.nodelist);
        listNote = new ArrayList<>();
        ArrayAdapter<Node> adapter =
                new ArrayAdapter<Node>(
                        MainActivity.this,
                        android.R.layout.simple_list_item_1,
                        listNote);
        listViewNode.setAdapter(adapter);

        listViewNode.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Node node = (Node) parent.getAdapter().getItem(position);
                Toast.makeText(MainActivity.this,
                        "MAC:\t" + node.mac + "\n" +
                                "IP:\t" + node.ip + "\n" +
                                "company:\t" + node.company + "\n" +
                                "country:\t" + node.country + "\n" +
                                "addressL1:\t" + node.addressL1 + "\n" +
                                "addressL2:\t" + node.addressL2 + "\n" +
                                "addressL3:\t" + node.addressL3 + "\n" +
                                "type:\t" + node.type + "\n" +
                                "startHex:\t" + node.startHex + "\n" +
                                "endHex:\t" + node.endHex + "\n" +
                                "startDec:\t" + node.startDec + "\n" +
                                "endDec:\t" + node.endDec,
                        Toast.LENGTH_SHORT).show();
            }
        });

        btnRead.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new TaskReadAddresses(listNote, listViewNode).execute();
            }
        });
    }



    class Node {
        String ip;
        String mac;

        String jsonBody;
        String startHex;
        String endHex;
        String startDec;
        String endDec;
        String company;
        String addressL1;
        String addressL2;
        String addressL3;
        String country;
        String type;

        String remark;

        String queryString = "http://www.macvendorlookup.com/api/v2/";

        Node(String ip, String mac){
            this.ip = ip;
            this.mac = mac;
            queryMacVendorLookup();
        }

        @Override
        public String toString() {
            return "IP: " + ip + "\n" + "MAC: " + mac + "\n" + company + "\n" + remark;
        }

        private String sendQuery(String qMac) throws IOException{
            String result = "";

            URL searchURL = new URL(queryString + qMac);

            HttpURLConnection httpURLConnection = (HttpURLConnection) searchURL.openConnection();

            if(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK){
                InputStreamReader inputStreamReader = new InputStreamReader(httpURLConnection.getInputStream());
                BufferedReader bufferedReader = new BufferedReader(
                        inputStreamReader,
                        8192);

                String line = null;
                while((line = bufferedReader.readLine()) != null){
                    result += line;
                }

                bufferedReader.close();
            }

            return result;
        }


        private void ParseResult(String json){

            try {
                JSONArray jsonArray = new JSONArray(json);
                JSONObject jsonObject = (JSONObject) jsonArray.get(0);
                startHex = jsonObject.getString("startHex");
                endHex = jsonObject.getString("endHex");
                startDec = jsonObject.getString("startDec");
                endDec = jsonObject.getString("endDec");
                company = jsonObject.getString("company");
                addressL1 = jsonObject.getString("addressL1");
                addressL2 = jsonObject.getString("addressL2");
                addressL3 = jsonObject.getString("addressL3");
                country = jsonObject.getString("country");
                type = jsonObject.getString("type");
                remark = "OK";

            } catch (JSONException e) {
                e.printStackTrace();
                remark = e.getMessage();
            }

        }

        private void queryMacVendorLookup(){
            try {
                jsonBody = sendQuery(mac);
                ParseResult(jsonBody);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private class TaskReadAddresses extends AsyncTask<Void, Node, Void> {

        ArrayList<Node> array;
        ListView listView;

        TaskReadAddresses(ArrayList<Node> array, ListView v){
            listView = v;
            this.array = array;
            array.clear();
            textResult.setText("querying...");
        }

        @Override
        protected Void doInBackground(Void... params) {
            readAddresses();

            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            textResult.setText("Done");
        }

        @Override
        protected void onProgressUpdate(Node... values) {
            listNote.add(values[0]);
            ((ArrayAdapter)(listView.getAdapter())).notifyDataSetChanged();

        }

        private void readAddresses() {

            BufferedReader bufferedReader = null;

            try {
                bufferedReader = new BufferedReader(new FileReader("/proc/net/arp"));

                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    String[] splitted = line.split(" +");
                    if (splitted != null && splitted.length >= 4) {
                        String ip = splitted[0];
                        String mac = splitted[3];
                        if (mac.matches("..:..:..:..:..:..")) {
                            Node thisNode = new Node(ip, mac);
                            publishProgress(thisNode);
                        }
                    }
                }

            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally{
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:padding="16dp"
    android:orientation="vertical"
    tools:context="com.blogspot.android_er.androidlistclient.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/readclient"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="Read Ip/MAC addresses"/>

    <TextView
        android:id="@+id/result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <ListView
        android:id="@+id/nodelist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>


uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml

download filesDownload runnable APK .

Next:
Get HostName of WiFi hotspot clients, and check if it is still connected.

Retrieve IP and MAC addresses from /proc/net/arp

Last post "Display WiFi Hotspot clients by "cat /proc/net/arp"" display arp as human readable string, but not machine readable. It's another version to retrieve IP and MAC addresses, store in a ArrayList.


MainActivity.java
package com.blogspot.android_er.androidlistclient;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    Button btnRead;
    TextView textResult;

    ArrayList<Node> listNote;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnRead = (Button)findViewById(R.id.readclient);
        textResult = (TextView)findViewById(R.id.result);

        listNote = new ArrayList<>();

        btnRead.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                readAddresses();
                textResult.setText("");
                for(int i=0; i<listNote.size(); i++){
                    textResult.append(i + " ");
                    textResult.append(listNote.get(i).toString());
                    textResult.append("\n");
                }
            }
        });
    }

    private void readAddresses() {
        listNote.clear();
        BufferedReader bufferedReader = null;

        try {
            bufferedReader = new BufferedReader(new FileReader("/proc/net/arp"));

            String line;
            while ((line = bufferedReader.readLine()) != null) {
                String[] splitted = line.split(" +");
                if (splitted != null && splitted.length >= 4) {
                    String ip = splitted[0];
                    String mac = splitted[3];
                    if (mac.matches("..:..:..:..:..:..")) {
                        Node thisNode = new Node(ip, mac);
                        listNote.add(thisNode);
                    }
                }
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            try {
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    class Node {
        String ip;
        String mac;

        Node(String ip, String mac){
            this.ip = ip;
            this.mac = mac;
        }

        @Override
        public String toString() {
            return ip + " " + mac;
        }
    }
}


layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:padding="16dp"
    android:orientation="vertical"
    tools:context="com.blogspot.android_er.androidlistclient.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/readclient"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="Read Ip/MAC addresses"/>

    <TextView
        android:id="@+id/result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:typeface="monospace"
        android:textSize="24sp"/>
</LinearLayout>


Next:
Lookup manufacturer info by MAC address, using www.macvendorlookup.com API
Get HostName of WiFi hotspot clients, and check if it is still connected

Display WiFi Hotspot clients by "cat /proc/net/arp"

This example display WiFi Hotspot connected clients (with IP and MAC address) by Linux command "cat /proc/net/arp", using ProcessBuilder.

(You can download runnable APK from link on bottom)

Tethering OFF, as WiFi client.

Tethering ON, with no client connected.

Tethering ON, with two clients connected; Nexus 7 and Raspberry Pi + WiFi dongle.

But, after any client disconnected, the /proc/net/arp will not updated immediately; I don't know how long it will refresh. One way to update arp is turn OFF and ON tethering again.

Tested on unrooted Xiaomi Redmi 2 running Android 4.4.4.

MainActivity.java
package com.blogspot.android_er.androidlistclient;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.IOException;
import java.io.InputStream;

public class MainActivity extends AppCompatActivity {

    Button btnRead;
    TextView textResult;

    //String[] args = {"/system/bin/cat", "/proc/net/arp"};
    String[] args = {"cat", "/proc/net/arp"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnRead = (Button)findViewById(R.id.readclient);
        textResult = (TextView)findViewById(R.id.result);

        btnRead.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textResult.setText(toRead());
            }
        });
    }

    private String toRead()
    {
        ProcessBuilder cmd;
        String result="";

        try{
            cmd = new ProcessBuilder(args);

            Process process = cmd.start();
            InputStream in = process.getInputStream();
            byte[] re = new byte[1024];
            while(in.read(re) != -1){
                System.out.println(new String(re));
                result = result + new String(re);
            }
            in.close();
        } catch(IOException ex){
            ex.printStackTrace();
        }
        return result;
    }
}


layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:padding="16dp"
    android:orientation="vertical"
    tools:context="com.blogspot.android_er.androidlistclient.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <Button
        android:id="@+id/readclient"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="Read /proc/net/arp"/>

    <TextView
        android:id="@+id/result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:typeface="monospace"
        android:textSize="12sp"/>
</LinearLayout>


download filesDownload runnable APK .

This example display arp in human readable format, but not for machine. Next post "Retrieve IP and MAC addresses from /proc/net/arp" get it in more machine readable.

Monday, January 5, 2015

File transfer via Socket, between Android devices

This example show how to transfer file between Android devices, via Socket.

In server side, it start a Thread to run a ServerSocket and wait for connection. Once connected, start another Thread to send file.

In client side, start a Thread to connect to server and download file.

In this example, the file to send and receive are fixed test.txt in external storage.



Server Side:

MainActivity.java
package com.example.androidsocketfiletransferserver;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.os.Environment;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

 TextView infoIp, infoPort;

 static final int SocketServerPORT = 8080;
 ServerSocket serverSocket;
 
 ServerSocketThread serverSocketThread;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  infoIp = (TextView) findViewById(R.id.infoip);
  infoPort = (TextView) findViewById(R.id.infoport);

  infoIp.setText(getIpAddress());
  
  serverSocketThread = new ServerSocketThread();
  serverSocketThread.start();
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  
  if (serverSocket != null) {
   try {
    serverSocket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }

 private String getIpAddress() {
  String ip = "";
  try {
   Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
     .getNetworkInterfaces();
   while (enumNetworkInterfaces.hasMoreElements()) {
    NetworkInterface networkInterface = enumNetworkInterfaces
      .nextElement();
    Enumeration<InetAddress> enumInetAddress = networkInterface
      .getInetAddresses();
    while (enumInetAddress.hasMoreElements()) {
     InetAddress inetAddress = enumInetAddress.nextElement();

     if (inetAddress.isSiteLocalAddress()) {
      ip += "SiteLocalAddress: "
        + inetAddress.getHostAddress() + "\n";
     }

    }

   }

  } catch (SocketException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   ip += "Something Wrong! " + e.toString() + "\n";
  }

  return ip;
 }
 
 public class ServerSocketThread extends Thread {

  @Override
  public void run() {
   Socket socket = null;
   
   try {
    serverSocket = new ServerSocket(SocketServerPORT);
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      infoPort.setText("I'm waiting here: " 
       + serverSocket.getLocalPort());
     }});
    
    while (true) {
     socket = serverSocket.accept();
     FileTxThread fileTxThread = new FileTxThread(socket);
     fileTxThread.start();
    }
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } finally {
    if (socket != null) {
     try {
      socket.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
   }
  }

 }
 
 public class FileTxThread extends Thread {
  Socket socket;
  
  FileTxThread(Socket socket){
   this.socket= socket;
  }

  @Override
  public void run() {
   File file = new File(
     Environment.getExternalStorageDirectory(), 
     "test.txt");
   
   byte[] bytes = new byte[(int) file.length()];
   BufferedInputStream bis;
   try {
    bis = new BufferedInputStream(new FileInputStream(file));
    bis.read(bytes, 0, bytes.length);
    OutputStream os = socket.getOutputStream();
    os.write(bytes, 0, bytes.length);
    os.flush();
    socket.close();
    
    final String sentMsg = "File sent to: " + socket.getInetAddress();
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      Toast.makeText(MainActivity.this, 
        sentMsg, 
        Toast.LENGTH_LONG).show();
     }});
    
   } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } finally {
    try {
     socket.close();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
   
  }
 }
}

activity_main.xml
<LinearLayout 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:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidsocketfiletransferserver.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="File Transfer Server"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/infoport"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textStyle="italic" />

    <TextView
        android:id="@+id/infoip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textStyle="italic" />

</LinearLayout>

Add permission of "android.permission.INTERNET" and "android.permission.READ_EXTERNAL_STORAGE" to AndroidManifest.xml.

download filesDownload the files.


Client Side:

MainActivity.java
package com.example.androidsocketfiletransferclient;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.os.Bundle;
import android.os.Environment;

public class MainActivity extends ActionBarActivity {

 EditText editTextAddress;
 Button buttonConnect;
 TextView textPort;

 static final int SocketServerPORT = 8080;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  editTextAddress = (EditText) findViewById(R.id.address);
  textPort = (TextView) findViewById(R.id.port);
  textPort.setText("port: " + SocketServerPORT);
  buttonConnect = (Button) findViewById(R.id.connect);
  
  buttonConnect.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    ClientRxThread clientRxThread = 
     new ClientRxThread(
      editTextAddress.getText().toString(), 
      SocketServerPORT);
    
    clientRxThread.start();
   }});
 }

 private class ClientRxThread extends Thread {
  String dstAddress;
  int dstPort;

  ClientRxThread(String address, int port) {
   dstAddress = address;
   dstPort = port;
  }

  @Override
  public void run() {
   Socket socket = null;
   
   try {
    socket = new Socket(dstAddress, dstPort);
    
    File file = new File(
      Environment.getExternalStorageDirectory(), 
      "test.txt");
    
    byte[] bytes = new byte[1024];
    InputStream is = socket.getInputStream();
       FileOutputStream fos = new FileOutputStream(file);
       BufferedOutputStream bos = new BufferedOutputStream(fos);
       int bytesRead = is.read(bytes, 0, bytes.length);
       bos.write(bytes, 0, bytesRead);
       bos.close();
       socket.close();
       
       MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      Toast.makeText(MainActivity.this, 
        "Finished", 
        Toast.LENGTH_LONG).show();
     }});
    
   } catch (IOException e) {

    e.printStackTrace();
    
    final String eMsg = "Something wrong: " + e.getMessage();
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      Toast.makeText(MainActivity.this, 
        eMsg, 
        Toast.LENGTH_LONG).show();
     }});
    
   } finally {
    if(socket != null){
     try {
      socket.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
   }
  }
 }

}

activity_main.xml
<LinearLayout 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:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidsocketfiletransferclient.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="File Transfer Client"
        android:textStyle="bold" />

    <EditText
        android:id="@+id/address"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="dstAddress" />

    <TextView
        android:id="@+id/port"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/connect"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Connect..." />

</LinearLayout>

Add permission of "android.permission.INTERNET" and "android.permission.WRITE_EXTERNAL_STORAGE" to AndroidManifest.xml.

download filesDownload the files.


Next:
Transfer image between Android devices, via Socket

More example of Android Network programming
- Bi-directional communication between Client and Server, using ServerSocket, Socket, DataInputStream and DataOutputStream

Sunday, March 2, 2014

Saturday, February 8, 2014

Android Server/Client example - client side using Socket

It's the client side implementation of our Server/Client example, the server side is listed in last post "server side using ServerSocket".

Android client side using Socket
Android client side using Socket

package com.example.androidclient;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {
 
 TextView textResponse;
 EditText editTextAddress, editTextPort; 
 Button buttonConnect, buttonClear;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  editTextAddress = (EditText)findViewById(R.id.address);
  editTextPort = (EditText)findViewById(R.id.port);
  buttonConnect = (Button)findViewById(R.id.connect);
  buttonClear = (Button)findViewById(R.id.clear);
  textResponse = (TextView)findViewById(R.id.response);
  
  buttonConnect.setOnClickListener(buttonConnectOnClickListener);
  
  buttonClear.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    textResponse.setText("");
   }});
 }
 
 OnClickListener buttonConnectOnClickListener = 
   new OnClickListener(){

    @Override
    public void onClick(View arg0) {
     MyClientTask myClientTask = new MyClientTask(
       editTextAddress.getText().toString(),
       Integer.parseInt(editTextPort.getText().toString()));
     myClientTask.execute();
    }};

 public class MyClientTask extends AsyncTask<Void, Void, Void> {
  
  String dstAddress;
  int dstPort;
  String response = "";
  
  MyClientTask(String addr, int port){
   dstAddress = addr;
   dstPort = port;
  }

  @Override
  protected Void doInBackground(Void... arg0) {
   
   Socket socket = null;
   
   try {
    socket = new Socket(dstAddress, dstPort);
    
    ByteArrayOutputStream byteArrayOutputStream = 
                  new ByteArrayOutputStream(1024);
    byte[] buffer = new byte[1024];
    
    int bytesRead;
    InputStream inputStream = socket.getInputStream();
    
    /*
     * notice:
     * inputStream.read() will block if no data return
     */
             while ((bytesRead = inputStream.read(buffer)) != -1){
                 byteArrayOutputStream.write(buffer, 0, bytesRead);
                 response += byteArrayOutputStream.toString("UTF-8");
             }

   } catch (UnknownHostException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    response = "UnknownHostException: " + e.toString();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    response = "IOException: " + e.toString();
   }finally{
    if(socket != null){
     try {
      socket.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
   }
   return null;
  }

  @Override
  protected void onPostExecute(Void result) {
   textResponse.setText(response);
   super.onPostExecute(result);
  }
  
 }

}

<LinearLayout 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:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <EditText 
        android:id="@+id/address"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="dstAddress" />
    <EditText 
        android:id="@+id/port"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="dstPort" />
    <Button 
        android:id="@+id/connect"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Connect..."/>
    <Button 
        android:id="@+id/clear"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Clear"/>
    <TextView
        android:id="@+id/response"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

Remark: uses-permission of "android.permission.INTERNET" is needed.

download filesDownload the files.



Related:
- Node.js server communicate with Android client

*** Updated example: Bi-directional communication between Client and Server, using ServerSocket, Socket, DataInputStream and DataOutputStream.

Android Server/Client example - server side using ServerSocket

It's the server side implementation of our Server/Client example, the client side is listed in next post "client side using Socket".

Android Server using ServerSocket
Android Server using ServerSocket
In this server side implementation, it will list its own IP address when program start. And run in background thread, start a ServerSocket and wait at serverSocket.accept(). Once any request received, it return a message to client side.

package com.example.androidserversocket;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;

import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;

public class MainActivity extends Activity {

 TextView info, infoip, msg;
 String message = "";
 ServerSocket serverSocket;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  info = (TextView) findViewById(R.id.info);
  infoip = (TextView) findViewById(R.id.infoip);
  msg = (TextView) findViewById(R.id.msg);
  
  infoip.setText(getIpAddress());

  Thread socketServerThread = new Thread(new SocketServerThread());
  socketServerThread.start();
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();

  if (serverSocket != null) {
   try {
    serverSocket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }

 private class SocketServerThread extends Thread {

  static final int SocketServerPORT = 8080;
  int count = 0;

  @Override
  public void run() {
   try {
    serverSocket = new ServerSocket(SocketServerPORT);
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      info.setText("I'm waiting here: "
        + serverSocket.getLocalPort());
     }
    });

    while (true) {
     Socket socket = serverSocket.accept();
     count++;
     message += "#" + count + " from " + socket.getInetAddress()
       + ":" + socket.getPort() + "\n";

     MainActivity.this.runOnUiThread(new Runnable() {

      @Override
      public void run() {
       msg.setText(message);
      }
     });

     SocketServerReplyThread socketServerReplyThread = new SocketServerReplyThread(
       socket, count);
     socketServerReplyThread.run();

    }
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

 }

 private class SocketServerReplyThread extends Thread {

  private Socket hostThreadSocket;
  int cnt;

  SocketServerReplyThread(Socket socket, int c) {
   hostThreadSocket = socket;
   cnt = c;
  }

  @Override
  public void run() {
   OutputStream outputStream;
   String msgReply = "Hello from Android, you are #" + cnt;

   try {
    outputStream = hostThreadSocket.getOutputStream();
             PrintStream printStream = new PrintStream(outputStream);
             printStream.print(msgReply);
             printStream.close();

    message += "replayed: " + msgReply + "\n";

    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      msg.setText(message);
     }
    });

   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    message += "Something wrong! " + e.toString() + "\n";
   }

   MainActivity.this.runOnUiThread(new Runnable() {

    @Override
    public void run() {
     msg.setText(message);
    }
   });
  }

 }

 private String getIpAddress() {
  String ip = "";
  try {
   Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
     .getNetworkInterfaces();
   while (enumNetworkInterfaces.hasMoreElements()) {
    NetworkInterface networkInterface = enumNetworkInterfaces
      .nextElement();
    Enumeration<InetAddress> enumInetAddress = networkInterface
      .getInetAddresses();
    while (enumInetAddress.hasMoreElements()) {
     InetAddress inetAddress = enumInetAddress.nextElement();

     if (inetAddress.isSiteLocalAddress()) {
      ip += "SiteLocalAddress: " 
        + inetAddress.getHostAddress() + "\n";
     }
     
    }

   }

  } catch (SocketException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   ip += "Something Wrong! " + e.toString() + "\n";
  }

  return ip;
 }
}

<LinearLayout 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:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/infoip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <TextView
            android:id="@+id/msg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </ScrollView>

</LinearLayout>

Remark: uses-permission of "android.permission.INTERNET" is needed.

download filesDownload the files.



*** Updated example: Bi-directional communication between Client and Server, using ServerSocket, Socket, DataInputStream and DataOutputStream.