2
\$\begingroup\$

I've just begun programming Java and I'm working on the following code that deals with socket-based communications. Basically it connects to a client on port 8888:

Gist of code

package com.mobile.stoq.stoqpay;

import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

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

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Set;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.widget.Toast;

import com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.common.api.GoogleApiClient;

import stone.application.enums.ErrorsEnum;
import stone.application.enums.InstalmentTransactionEnum;
import stone.application.enums.TypeOfTransactionEnum;
import stone.application.interfaces.StoneCallbackInterface;
import stone.providers.BluetoothConnectionProvider;
import stone.providers.LoadTablesProvider;
import stone.providers.TransactionProvider;
import stone.utils.GlobalInformations;
import stone.utils.PinpadObject;
import stone.providers.DisplayMessageProvider;
import stone.utils.StoneTransaction;

public class MainActivity extends AppCompatActivity {
    private BufferedReader in;
    private PrintWriter out;
    private ServerSocket server;
    private boolean isConnected = false;
    private PinpadObject pinpadSelected;
    private final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    /**
     * ATTENTION: This was auto-generated to implement the App Indexing API.
     * See https://g.co/AppIndexing/AndroidStudio for more information.
     */
    private GoogleApiClient client2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        turnBluetoothOn();
        // Networking can't happen on the main thread so we make a new one
        new Thread(new Runnable() {
            public void run() {
                String inMsg;
                JSONObject fromClient;
                tryConnect(); // Attempts connection.
                while (true) {
                    try {
                        inMsg = in.readLine();
                        // The message being null implies a loss of connection, so we recPinpadObject pinpad, BluetoothConnectionProvider
                        if (inMsg == null) {
                            server.close();
                            pinUnPar();
                            turnBluetoothOn();
                            tryConnect();
                            continue;
                        }
                        // Converts the message to JSON
                        fromClient = new JSONObject(inMsg);
                        System.out.println("In: " + fromClient);
                        final String cmd = fromClient.getString("command"); // Parses the command
                        final JSONArray args = fromClient.getJSONArray("args"); // Parses the arguments
                        // Series of if statements to interpret commands
                        switch (cmd) {
                            case "list": // Lists all available bluetooth devices
                                if (args.length() < 1) {
                                    out.println("Incorrect number of arguments for \"list\"");
                                }
                                if (args.getString(0).equals("devices")) {
                                    String devices = "devices{";
                                    BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
                                    Set<BluetoothDevice> pairedDevices = btAdapter.getBondedDevices();
                                    if (pairedDevices.size() > 0) {
                                        for (BluetoothDevice device : pairedDevices) {
                                            devices += String.format("{name:%s, address:%s}", device.getName(), device.getAddress());
                                        }
                                        out.println(devices + "}");
                                    } else {
                                        out.println("No paired devices");
                                    }

                                } else {
                                    out.println("Unknown argument for \"list\"");
                                }
                                break;
                            case "connect": // Connects to a pinpad device
                                if (args.length() != 2) {
                                    out.println("Incorrect number of arguments for \"connect\"");
                                    continue;
                                }
                                pinPar(args.getString(0), args.getString(1));
                                break;
                            case "disconnect": // Disconnects
                                if(!isConnected){
                                    out.println("You are not connected to a valid device.");
                                    continue;
                                }
                                pinUnPar();
                                break;
                            case "print": // Prints to the pinpad's display
                                if (args.length() < 1) {
                                    out.println("Incorrect number of arguments for \"print\"");
                                    continue;
                                }
                                if(!isConnected){
                                    out.println("You are not connected to a valid device.");
                                    continue;
                                }
                                String say = "";
                                for (int i = 0; i < args.length(); i++) {
                                    say += args.getString(i) + " ";
                                }
                                System.out.println(say);
                                pinPrint(say, true);
                                break;
                            case "trans": // Handles transactions.
                                if (args.length() < 3) {
                                    out.println("Incorrect number of arguments for \"trans\"");
                                    continue;
                                }
                                if(!isConnected){
                                    out.println("You are not connected to a valid device.");
                                    continue;
                                }
                                pinTrans(args.getString(0), args.getString(1), args.getString(2), "0");
                                break;
                            default: // Handles unknown commands.
                                out.println("Unknown command \"" + cmd + "\"");
                                break;
                        }
                    } catch (Exception e) {
                        try {
                            server.close();
                            tryConnect();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                            break;
                        }
                    }
                }
            }
        }).start();
        // ATTENTION: This was auto-generated to implement the App Indexing API.
        // See https://g.co/AppIndexing/AndroidStudio for more information.
        client2 = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
    }

    private void tryConnect() { //Attempts a connection to the client
        try {
            int port = 8888;
            server = new ServerSocket(port);
            System.out.println("Waiting for client on port " + port);
            Socket client = server.accept();
            System.out.println("Just connected to " + client.getRemoteSocketAddress());
            // Starts a new reader on the client input stream
            in = new BufferedReader(new InputStreamReader(client.getInputStream()));
            // Starts a new writer to the client output streamPinpadObject pinpad, BluetoothConnectionProvider conn
            out = new PrintWriter(client.getOutputStream(), true);
        } catch (IOException IOError) {
            IOError.printStackTrace();
        }
    }

    private void turnBluetoothOn() { //Toggles bluetooth
        if (mBluetoothAdapter == null) {
            Toast.makeText(getApplicationContext(), "This device does not support Bluetooth", Toast.LENGTH_LONG).show();
        } else {
            if (!mBluetoothAdapter.isEnabled()) {
                try {
                    mBluetoothAdapter.enable();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void pinPar(final String name, final String address) { //Connects to a pinpad (credit card machine)
        MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                pinpadSelected = new PinpadObject(name, address, false);
                BluetoothConnectionProvider bluetoothConnectionProvider = new BluetoothConnectionProvider(MainActivity.this, pinpadSelected);
                bluetoothConnectionProvider.setDialogMessage("Connecting to pinpad");
                bluetoothConnectionProvider.setWorkInBackground(false);
                bluetoothConnectionProvider.setConnectionCallback(new StoneCallbackInterface() {
                                                                      @Override
                                                                      public void onSuccess() {
                                                                          isConnected = true;
                                                                          Toast.makeText(getApplicationContext(), "Pinpad connected", Toast.LENGTH_SHORT).show();
                                                                          out.println("Connected to " + name + " at " + address);
                                                                          pinPrint("Stoq      ", false);

                                                                      }

                                                                      @Override
                                                                      public void onError() {
                                                                          isConnected = false;
                                                                          Toast.makeText(getApplicationContext(), "Connection failed", Toast.LENGTH_SHORT).show();
                                                                          out.println("Failed connecting to " + name + " at " + address);
                                                                      }
                                                                  }

                );
                bluetoothConnectionProvider.execute();
            }
        });
    }

    private void pinUnPar() { // Disconnects the pinpad
        //TODO: Hackish way of disconnecting the pinpad, must find a proper way.
        try {
            mBluetoothAdapter.disable();
            android.os.SystemClock.sleep(10);
            mBluetoothAdapter.enable();
            MainActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "Pinpad disconnected", Toast.LENGTH_SHORT).show();
                }
            });
            out.println(pinpadSelected.getName() + " disconnected.");
            isConnected = false;
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void pinPrint(final String text, final boolean doOutput) { // Prints to the pinpad's screen
        MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                DisplayMessageProvider display = new DisplayMessageProvider(getApplicationContext(), text, pinpadSelected);
                if (doOutput) {
                    display.setConnectionCallback(new StoneCallbackInterface() {
                        @Override
                        public void onSuccess() {
                            out.println("Printed");
                        }

                        @Override
                        public void onError() {
                            out.println("Printing failed");
                        }
                    });
                }
                display.execute();
            }
        });
    }

    private void pinTrans(final String type, final String val, final String installments, final String interest) { // Starts a transaction with the pinpad
        MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (GlobalInformations.isConnectedToPinpad()) {
                    StoneTransaction stoneTransaction = new StoneTransaction(pinpadSelected);
                    stoneTransaction.setAmount(val);
                    stoneTransaction.setEmailClient(null);
                    stoneTransaction.setRequestId(null);
                    stoneTransaction.setUserModel(GlobalInformations.getUserModel(0));

                    //TODO: This is sorta hackish, and I only did it this way because I couldn't make
                    //sense out of the solution I got off code review (http://goo.gl/35kXdn). Should
                    //try to implement that one some day.
                    boolean hasInterest = false;
                    if (interest.toLowerCase().equals("true") || interest.equals("1")){
                        hasInterest = true;
                    }
                    int index = (Integer.parseInt(installments) - 1) + (hasInterest ? 0 : 11);
                    InstalmentTransactionEnum installs = InstalmentTransactionEnum.values()[index];
                    stoneTransaction.setInstalmentTransactionEnum(installs);

                    if (type.equals("CREDIT")) {
                        stoneTransaction.setTypeOfTransaction(TypeOfTransactionEnum.CREDIT);
                    } else {
                        stoneTransaction.setTypeOfTransaction(TypeOfTransactionEnum.DEBIT);
                    }

                    final TransactionProvider provider = new TransactionProvider(MainActivity.this, stoneTransaction, pinpadSelected);
                    provider.setDialogMessage("Sending");
                    provider.setDialogTitle("Please wait");
                    provider.setWorkInBackground(false);
                    provider.setConnectionCallback(new StoneCallbackInterface() {
                        @Override
                        public void onSuccess() {
                            System.out.println(provider.getTransactionStatus().toString());
                            System.out.println(provider.getMessageFromAuthorize());
                            Toast.makeText(getApplicationContext(), "Transaction sent successfully.", Toast.LENGTH_SHORT).show();
                            out.println(provider.getTransactionStatus().toString());
                        }
                        @Override
                        public void onError() {
                            if (provider.theListHasError(ErrorsEnum.NEED_LOAD_TABLES)) {
                                LoadTablesProvider loadTablesProvider = new LoadTablesProvider(MainActivity.this, provider.getGcrRequestCommand(), pinpadSelected);
                                loadTablesProvider.setDialogMessage("Uploading tables");
                                loadTablesProvider.setWorkInBackground(false);
                                loadTablesProvider.setConnectionCallback(new StoneCallbackInterface() {
                                    @Override
                                    public void onSuccess() {
                                        pinTrans(type, val, installments, interest);
                                    }

                                    @Override
                                    public void onError() {
                                        Toast.makeText(getApplicationContext(), "Updating tables failed", Toast.LENGTH_SHORT).show();
                                        out.println("Transaction failed.");
                                    }
                                });
                                loadTablesProvider.execute();
                            } else if (provider.theListHasError(ErrorsEnum.OPERATION_CANCELLED_BY_USER)) {
                                Toast.makeText(getApplicationContext(), "Operation cancelled by user", Toast.LENGTH_SHORT).show();
                                out.println("Operation cancelled by user");

                            } else {
                                Toast.makeText(getApplicationContext(), "Transaction failed.", Toast.LENGTH_SHORT).show();
                                out.println("Transaction failed");
                            }
                        }
                    });
                    provider.execute();
                }
            }
        });

    }

    @Override
    public void onStart() {
        super.onStart();

        // ATTENTION: This was auto-generated to implement the App Indexing API.
        // See https://g.co/AppIndexing/AndroidStudio for more information.
        client2.connect();
        Action viewAction = Action.newAction(
                Action.TYPE_VIEW, // TODO: choose an action type.
                "Main Page", // TODO: Define a title for the content shown.
                // TODO: If you have web page content that matches this app activity's content,
                // make sure this auto-generated web page URL is correct.
                // Otherwise, set the URL to null.
                Uri.parse("http://host/path"),
                // TODO: Make sure this auto-generated app deep link URI is correct.
                Uri.parse("android-app://com.mobile.stoq.stoqpay/http/host/path")
        );
        AppIndex.AppIndexApi.start(client2, viewAction);
    }

    @Override
    public void onStop() {
        super.onStop();

        // ATTENTION: This was auto-generated to implement the App Indexing API.
        // See https://g.co/AppIndexing/AndroidStudio for more information.
        Action viewAction = Action.newAction(
                Action.TYPE_VIEW, // TODO: choose an action type.
                "Main Page", // TODO: Define a title for the content shown.
                // TODO: If you have web page content that matches this app activity's content,
                // make sure this auto-generated web page URL is correct.
                // Otherwise, set the URL to null.
                Uri.parse("http://host/path"),
                // TODO: Make sure this auto-generated app deep link URI is correct.
                Uri.parse("android-app://com.mobile.stoq.stoqpay/http/host/path")
        );
        AppIndex.AppIndexApi.end(client2, viewAction);
        client2.disconnect();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            server.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Now, I'm positive that this code is filled with bad practices, but I can really fix those without knowing which are they, so I ask:

  1. What am I doing here that I shouldn't be doing?
  2. Where am I missing the opportunity to be elegant in my code?
  3. Any tips for someone coming from a pure C and Python background?
\$\endgroup\$
  • \$\begingroup\$ Your post is very vague about what this code does. Please describe its purpose better, and also retitle the question. (See How to Ask.) \$\endgroup\$ – 200_success Mar 8 '16 at 20:00
  • \$\begingroup\$ @200_success I've made some edits, let me know if you think it's better now. Thanks for the tip! \$\endgroup\$ – Bernardo Meurer Mar 8 '16 at 20:07
  • \$\begingroup\$ One small thing from this is to use English in your code would help other developers find it easier to read your code to review. \$\endgroup\$ – autobot_101 Mar 16 '16 at 3:50
  • \$\begingroup\$ @autobot_101 This code has been heavily changed (including that). Allow me to update that in the morning (midnight here currently) \$\endgroup\$ – Bernardo Meurer Mar 16 '16 at 3:52
  • \$\begingroup\$ @autobot_101 There you go, the whole new code. \$\endgroup\$ – Bernardo Meurer Mar 16 '16 at 14:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.