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\$
5
  • \$\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\$ Mar 8, 2016 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\$ Mar 8, 2016 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\$ Mar 16, 2016 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\$ Mar 16, 2016 at 3:52
  • \$\begingroup\$ @autobot_101 There you go, the whole new code. \$\endgroup\$ Mar 16, 2016 at 14:00

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.