{{announcement.body}}
{{announcement.title}}

Android Device Matching With Socket Programming

DZone 's Guide to

Android Device Matching With Socket Programming

In this article, I'll introduce the concept of socket and focus on how to use socket programming for consists of 2 separate Android devices connecting each other.

· Web Dev Zone ·
Free Resource

In this article, I would like to introduce the concept of socket and focus on how to use socket programming for consists of 2 separate Android devices connecting each other.

Let's first take a look at the concept of “socket”. 

When we say socket, a piece of hardware comes alive in our computer cases. However, the socket is a structure that enables the computer to communicate with other computers over the network. But we need some addresses to make this happen. That address is calling as the IP address of our computer.

The IP address allows us to determine which computer to communicate with. When we reach the computer we will communicate with, we need to specify which program we will contact. Right here, the ports of our computer come into play.

This means; the two computers communicate with each other through to the IP address and Port. The structure we will call and talking about the Socket consists of the IP address and Port binary. In other words, the socket is not a piece of hardware that is in the mind of everyone; It is a structure consisting of IP address and Port numbers.

There are multiple sockets on our computers. There are different ports on our computer for each socket-based program. 

As giving an example, 

1) FTP Servers use and communicate on Port 21
2) TELNET Servers use and communicate on Port 23.


I will show consists of taking the numbers that the client transmits to the server by squaring the server and transmitting it to the client again. Well, if you ask what is Client and Server, let's explain these two terms as follows;

The client is a processor that requests service in socket programs. When it wants, it connects to the server and makes the request and gets the returning answer and can disconnect it whenever it wants.

Server, on the other hand, is the server serving in socket programs. When the client wants to connect to the server, the server is always on to connect, and the client needs to monitor the port to which it will connect.

We briefly explained the Socket, now we can proceed to Socket Programming section

I believe the best way of learning new techniques or concepts based on way to step by step tutorial. In that article, you need to have Java and Android programming basics. 

So I will explain specific details and you can reach the repository and the source code of the app in my GitHub account in the below article.

Now, I aim to go through how to connect two android devices using socket communication, and later in the second part, we will see how to share files/data between two devices and make an application like Xender.

If you wonder Xender App, you can check it on that link ( http://web.xender.com/  )

I will present an example of an application. The application consists of taking 2 Android devices to connect.

1) First, you need to Android Studio environment and create new Project selecting language as Java

create new projectand select Java as language


2) We will create two buttons one for sending and one for receiving the data like below 

There are user guides on how to use it and 2 dummy buttons.

create two buttons


3) Location permission is required before starting hotspot service so that another device can see that device through wi-fi scanning

Java
 




xxxxxxxxxx
1
43


 
1
 /**
2
     * Show Location dialog
3
     */
4
    @Override
5
    public void requestLocationPermissionDialog() {
6
        new AlertDialog.Builder(mainActivity, R.style.Theme_AppCompat_Light_Dialog_Alert)
7
                .setTitle(R.string.title_location_services)
8
                .setCancelable(false)
9
                .setMessage(R.string.message_location_services)
10
                .setNegativeButton(R.string.action_cancel, (dialog, which) -> {
11
                    resetEverything("location cancel");
12
                })
13
                .setPositiveButton(R.string.action_enable, (dialogInterface, i) -> {
14
                    Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
15
                    startActivityForResult(intent, ACTION_LOCATION_SOURCE_SETTINGS);
16
                })
17
                .show();
18
    }
19
 
          
20
 
          
21
     // Once location permission is enabled request for write setting permission as shown below
22
 
          
23
    /**
24
     * Request write setting permission
25
     */
26
    @Override
27
    public void requestWritePermission() {
28
        AlertDialog.Builder builder = new AlertDialog.Builder(mainActivity, R.style.Theme_AppCompat_Light_Dialog_Alert);
29
        builder.setCancelable(false);
30
        builder.setTitle(mainActivity.getResources().getString(R.string.str_require_permission));
31
        builder.setMessage(mainActivity.getResources().getString(R.string.str_enable_write));
32
        builder.setPositiveButton("Yes", (dialog, which) -> {
33
            Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + mainActivity.getPackageName()));
34
            startActivityForResult(intent, PERMISSION_REQUEST_CODE_WRITE);
35
        });
36
        builder.setNegativeButton("No", (dialog, which) -> {
37
            resetEverything("Write permission no button");
38
            dialog.cancel();
39
        });
40
        builder.show();
41
 
          
42
    }
43
 
          



4) Here we have the permission confirmation screen

permission confirmation screen


5) After the user clicks on the send button we will create a local hotspot and shows the password in QR code, so a user can scan to connect to another device.

Note that there are small changes between Below Oreo Devices and others

a) Below Oreo, devices need to create a hotspot using WifiConfiguration as below

Java
 




xxxxxxxxxx
1


 
1
 WifiConfiguration wifiConfig = (WifiConfiguration) m.invoke(mWifiManager, null);
2
 wifiConfig.SSID = "AndroidShare_" + String.format("%04d",new           Random().nextInt(10000));
3
                    Log.d("Generated SSID", wifiConfig.SSID);
4
                
5
 
          



b) For Oreo and above devices need to use startLocalOnlyHotspot as shown below

Java
 




xxxxxxxxxx
1
32


1
WifiManager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {
2
 
          
3
                @Override
4
                public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
5
                    mReservation = reservation;
6
                    retry = 0;
7
                    startForeground(11,
8
                            buildForegroundNotification());
9
                    JSONObject jsonObject = new JSONObject();
10
                    try {
11
                        jsonObject.put(JsonHelper.SSID, reservation.getWifiConfiguration().SSID);
12
                        jsonObject.put(JsonHelper.Password, reservation.getWifiConfiguration().preSharedKey);
13
                        generateQRCode(reservation.getWifiConfiguration().SSID, jsonObject.toString());
14
                    } catch (JSONException e) {
15
                        e.printStackTrace();
16
                    }
17
                }
18
 
          
19
                public void onFailed(int i) {
20
                    super.onFailed(i);
21
                    if (retry < 2) {
22
                        retry++;
23
                        oreoAndAboveDevicesSetupHotspot();
24
                    }
25
                }
26
 
          
27
                public void onStopped() {
28
                    super.onStopped();
29
 
          
30
                }
31
            }, null);
32
 
          



6) Now you can put SSID and Password in the JSON object and then generate QR code using string. One hotspot is active listen to incoming connection request on a fixed port using socket server like below 

To generate a QR code QRGenerator library has been used and it is generated as shown below.

Java
 




xxxxxxxxxx
1


1
QRGEncoder qrgEncoder = new QRGEncoder(preSharedKey, null, QRGContents.Type.TEXT, smallerDimension);
2
     
3
Then wait for incoming socket connect request using ServerSocket
4
 
          
5
ServerSocket server = new ServerSocket(6678);
6
Socket socket = server.accept();
7
 
          



Here is the result of a "server" device. And it is ready to connection :)

ready for connection screen


7) Now let's work on the receiver part. 

To scan the QR code we need Camera permission, Location Permission and Wi-Fi should be on to scan nearby devices

Java
 




xxxxxxxxxx
1
87


1
@Override
2
    public ArrayList<String> checkAndRequestPermissions() {
3
        if (Build.VERSION.SDK_INT <= 21) {
4
            return new ArrayList<>();
5
        }
6
        int permissionCamera = ContextCompat.checkSelfPermission(
7
                mainActivity,
8
                Manifest.permission.ACCESS_FINE_LOCATION
9
        );
10
        int storage = ContextCompat.checkSelfPermission(mainActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
11
        int readStorage = ContextCompat.checkSelfPermission(mainActivity, Manifest.permission.READ_EXTERNAL_STORAGE);
12
        int camera = ContextCompat.checkSelfPermission(mainActivity, Manifest.permission.CAMERA);
13
 
          
14
        ArrayList<String> listPermissionsNeeded = new ArrayList<>();
15
 
          
16
 
          
17
        if (storage != PackageManager.PERMISSION_GRANTED) {
18
            listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
19
        }
20
 
          
21
        if (permissionCamera != PackageManager.PERMISSION_GRANTED) {
22
            listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
23
        }
24
 
          
25
        if (readStorage != PackageManager.PERMISSION_GRANTED) {
26
            listPermissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
27
        }
28
 
          
29
        if (isReceiver) {
30
 
          
31
            if (camera != PackageManager.PERMISSION_GRANTED) {
32
                listPermissionsNeeded.add(Manifest.permission.CAMERA);
33
            }
34
        }
35
 
          
36
 
          
37
        return listPermissionsNeeded;
38
    }
39
 
          
40
 
          
41
  @Override
42
    @TargetApi(Build.VERSION_CODES.M)
43
    public void requestPermission(ArrayList<String> listPermissionsNeeded) {
44
        String[] array = new String[listPermissionsNeeded.size()];
45
 
          
46
        for (int i = 0; i < listPermissionsNeeded.size(); i++) {
47
            array[i] = listPermissionsNeeded.get(i);
48
        }
49
        if (listPermissionsNeeded.size() > 0) {
50
            if (ActivityCompat.shouldShowRequestPermissionRationale(
51
                    mainActivity,
52
                    Manifest.permission.READ_EXTERNAL_STORAGE
53
            ) || ActivityCompat.shouldShowRequestPermissionRationale(
54
                    mainActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE
55
            ) || ActivityCompat.shouldShowRequestPermissionRationale(mainActivity, Manifest.permission.ACCESS_FINE_LOCATION) || ActivityCompat.shouldShowRequestPermissionRationale(mainActivity, Manifest.permission.CAMERA)
56
            ) {
57
                prefs.edit().putBoolean(PreferenceHelper.PermissionAsked, true).apply();
58
                requestPermissions(
59
                        array,
60
                        PERMISSION_REQUEST_CODE
61
                );
62
            } else {
63
                if (isReceiver) {
64
                    if (prefs.getBoolean(PreferenceHelper.PermissionCameraAsked, false)) {
65
                        requestPermissionDialog();
66
                    } else {
67
                        prefs.edit().putBoolean(PreferenceHelper.PermissionCameraAsked, true).apply();
68
                        requestPermissions(
69
                                array,
70
                                PERMISSION_REQUEST_CODE
71
                        );
72
                    }
73
                } else {
74
                    if (prefs.getBoolean(PreferenceHelper.PermissionAsked, false)) {
75
                        requestPermissionDialog();
76
                    } else {
77
                        prefs.edit().putBoolean(PreferenceHelper.PermissionAsked, true).apply();
78
                        requestPermissions(
79
                                array,
80
                                PERMISSION_REQUEST_CODE
81
                        );
82
                    }
83
                }
84
            }
85
        }
86
    }
87
 
          



permission screen for allowing app to take pictures and video


8) After permission, it will start scanning the devices using WifiManager getScanResults() method

Pulsator4droid is used to show pulse effects while scanning. Use mWifiManager.startScan() to start scanning and mWifiManager.getScanResults() will give a list of nearby devices in callback once scanning is done.

At below screenshot, is searching for new devices.

searching for new devices screen


9) Once the device is detected it will show the device name as shown below. Tap on the device to connect and it will open the QR scan screen, add network using SSID and Password then connect to the socket using connected server IP and fixed port.

To scan the QRcode add QRCodeScanner dependency and start scanning add below line

Java
 




xxxxxxxxxx
1


1
 Intent i = new Intent(mainActivity, QrCodeActivity.class);
2
 startActivityForResult(i, REQUEST_CODE_QR_SCAN); 
3
 
          



After scanning get SSDI and Password to connect with it as shown below

Java
 




xxxxxxxxxx
1
15


1
String result = data.getStringExtra("com.blikoon.qrcodescanner.got_qr_scan_relult");
2
                try {
3
                    JSONObject jsonObject = new JSONObject(result);
4
                    String SSID = jsonObject.getString(JsonHelper.SSID);
5
                    String Password = jsonObject.getString(JsonHelper.Password);
6
                    if (selectedItem.equals(SSID)) {
7
                        boolean isConnected = hotutil.connectToHotspot(SSID, Password);
8
                        if (isConnected)
9
                            bindNetworkProcess();
10
 
          
11
 
          
12
                } catch (JSONException e) {
13
                    e.printStackTrace();
14
                }
15
 
          



application screen


10) After taping on the device it will show connecting status as shown below

 Once a device is connected to a hotspot, connect to a socket to send data to another device 


Java
 




xxxxxxxxxx
1


1
Socket  s = new Socket();
2
s.setKeepAlive(true);
3
s.setSoLinger(true, 1000);
4
SocketAddress remoteAddress = new InetSocketAddress(getServerHost(), getServerPort());
5
s.connect(remoteAddress);
6
 
          



connection screen

11) Once the device is connected to a display device name send device model name from both the devices and on socket data received to display the device name

Java
 




xxxxxxxxxx
1


1
 JSONObject jsonObject = new JSONObject();
2
                    jsonObject.put(JsonHelper.connected, true);
3
                    jsonObject.put(JsonHelper.DeviceName, android.os.Build.MODEL);
4
                    TCPCommunicator.writeToSocket(jsonObject.toString() + "\n", new Handler());
5
 
          



Now we connected to the device


12) If you wish to disconnect from device send connection status false and close the server as shown below 

Java
 




xxxxxxxxxx
1


1
JSONObject jsonObject = new JSONObject();
2
  jsonObject.put(JsonHelper.connected, false);
3
 
          
4
 server.close();
5
 
          



As a result of steps, we see how to do consists of taking 2 Android devices to connect together. 

Next article I would like to show how to send data between two devices.



Credits

Pulsator4Droid

QRGenearator

QRCodeScanner


Source Code: https://github.com/omeryilmaz86/AndroidDataSharing.git

Topics:
android, socket programming

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}