Search code examples
javaandroidandroid-looper

Android client: Can't create handler inside thread that has not called Looper.prepare()


I have the following code from python server and java client working just fine. However I want to use this same concept to send a text message from a client with ssl from the android. The following are my code that I have written for Python and Java that works just fine.

Python Server Code :

import time
import glob
import os
import ssl, socket
from sh import ls


class serverText():

    host = ""
    def __init__(self, host, port):
        self.host = host
        self.port = port


    def wavFinder(self):
        try:
            newest = max(glob.iglob('*.[Ww][Aa][Vv]'), key=os.path.getctime)
            yield
        finally:
            print "no wav file here"


    def find_all(self, a_str, sub):
        start = 0
        while True:
            start = a_str.find(sub, start)
            if start == -1: return
            yield start
            start += len(sub)

    def get_IP_Edison(self,value=basestring):
        IP = os.popen(value).read()
        try :
            place = int(list(serverText.find_all(self, IP,":"))[1]+1)
        except:
            place = int(list(serverText.find_all(self, IP, ":"))[0] + 1)
        self.host = IP[place:-1]
        # return IP[tag1 + 1:tag2]

    def deal_with_client(self,connstream):
        timestr = time.strftime("%Y-%m-%d_%H-%M-%S")
        data = connstream.recv(1024)
        print data
        # null data means the client is finished with us
        while data:
            if not data:
                print 'no more data being sent'
                break
            data = connstream.recv(1024)
            print data
            # finished with client

    def start_Server(self):

        # calling the client context to loaded with
        context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)

        # CONFIGS--------
        # Key and cert created with OPENSSL
        key, cert = "/home/root/Coding/certificates/server/privKey.key", \
                    "/home/root/Coding/certificates/server/server.pem"

        # Load the certifications
        context.load_cert_chain(certfile=cert, keyfile=key)

        # calling the port and host / needs to be of the edison
        HOST = self.host
        PORT = self.port
        # create a normal socket
        bindsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # Bind the socket or create it
        bindsocket.bind((HOST, PORT))
        # make the socket listen on five connections
        bindsocket.listen(1)
        print 'Listening..on IP:' + str(HOST) + " and port:" + str(PORT)

        # accept the connection
        newsocket, fromaddr = bindsocket.accept()
        print 'accepted connection from' + str(fromaddr)
        # wrap it in socket but make sure keys match
        connstream = context.wrap_socket(newsocket, server_side=True,
                                         do_handshake_on_connect=True)
        try:
            # call the receive function to receive file (more details above )
            serverText.deal_with_client(self,connstream=connstream)
        finally:
            connstream.shutdown(socket.SHUT_RDWR)
            connstream.close()
            print 'socket was closed'


if __name__ == '__main__':
    startServer = serverText(host="",port=5000)
    value_school = '''ifconfig | grep "inet " | grep -v 127.0.0.1 | grep -v 192.* | awk '{print $2}' '''
    #value_home = '''ifconfig | grep "inet " | grep -v 127.* | awk '{print $2}' '''
    startServer.get_IP_Edison(value=value_school)
    print 'host is : '+ startServer.host
    print ls()
    startServer.wavFinder()
    startServer.start_Server()

This is my Java Code :

import java.io.*;
import java.net.*;
import java.security.*;

import javax.net.ssl.SSLSocketFactory;

import com.sun.net.ssl.SSLContext;
import com.sun.net.ssl.TrustManagerFactory;
import com.sun.net.ssl.TrustManager;

public class test {

    private static final String HOST = "192.168.0.103";

    private static final int PORT = 5000;
    final static String pathToStores = "/Users/admirmonteiro/Documents/Coding/Python/Thesis_Code/_Codes_/_Code_/Fall_15/fileTransmissionFiles/certs";
    final static String trustStoreFile = "cert.jks" ; // filename


    public static void main(String[] args) throws Exception {

        String currentDirectory;
        currentDirectory = System.getProperty("user.dir");
        System.out.println("Current working directory : "+currentDirectory);

        String trustFileName = pathToStores + "/" + trustStoreFile;

        char[] passphrase = "admir2006".toCharArray();
        KeyStore keystore = KeyStore.getInstance("JKS");
        keystore.load(new FileInputStream(trustFileName), passphrase);

        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(keystore);

        SSLContext context = SSLContext.getInstance("TLS");
        TrustManager[] trustManagers = tmf.getTrustManagers();

        context.init(null, trustManagers, null);

        SSLSocketFactory sf = context.getSocketFactory();

        Socket s = sf.createSocket(HOST, PORT);

        OutputStream out = s.getOutputStream();
        out.write("\n New Thing sent .\n\n".getBytes());


        out.close();
        s.close();
    }
}

I have the following android code which I updated but still having errors :

    Button sendButton;
    EditText textSend;
    private String ip_address = "192.168.10.103";
    private int port = 5000;


    private SSLSocket socket = null;
    private BufferedWriter out = null;
    private BufferedReader in = null;
    private final String TAG = "TAG";
    private char keystorepass[] = "......".toCharArray();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sendButton = (Button) findViewById(R.id.send);
        textSend = (EditText) findViewById(R.id.textsend);

        sendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String send = textSend.getText().toString();
                if(send.isEmpty()){
                    AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(MainActivity.this);
                    dialogBuilder.setMessage("Enter Text!");
                    dialogBuilder.setTitle("No TEXT");
                    dialogBuilder.setPositiveButton("OK...", null);
                    dialogBuilder.show();
                }else{
                    try {
                        KeyStore ks = KeyStore.getInstance("BKS");
                        InputStream keyin = getApplicationContext().getResources().openRawResource(R.raw.androidnewkey);
                        ks.load(keyin, keystorepass);
                        Log.i(TAG,"2");
                        SSLSocketFactory socketFactory = new SSLSocketFactory(ks);
                        socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                        socket = (SSLSocket)
                                socketFactory.createSocket(new Socket(ip_address,port), ip_address, port, false);
                        socket.startHandshake();
                        out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                        chat(send);

                    }catch (KeyStoreException e){
                        Log.i(TAG,"KeyStor");
                    }catch (IOException r ){
                        Log.i(TAG,"IO");
                    }catch(NoSuchAlgorithmException r ){
                        Log.i(TAG,"No all");
                    }catch (CertificateException u){
                        Log.i(TAG,"CertEx");
                    }catch(KeyManagementException r){
                        Log.i(TAG,"eyEx");
                    }catch(UnrecoverableKeyException e){
                        Log.i(TAG,"UnrectEx");
                    }
                }
            }
        });
    }
    public void chat(String temp){
        String message = temp;
        String line = "";
        // send id of the device to match with the image
        try {
            out.write(message+"\n");
            out.flush();
        } catch (IOException e2) {
            Log.i(TAG,"Read failed");
            System.exit(1);
        }
        // receive a ready command from the server
//        try {
//            line = in.readLine();
//            mResponse.setText("SERVER SAID: "+line);
//            //Log.i(TAG,line);
//        } catch (IOException e1) {
//            Log.i(TAG,"Read failed");
//            System.exit(1);
//        }
    }

When I type the message to be sent, here is the output(problem making the socket: why?):

Process: com.example.admirmonteiro.client, PID: 13539
android.os.NetworkOnMainThreadException                                                                                                                          
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1273)
at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:110)
at libcore.io.IoBridge.connectErrno(IoBridge.java:137)
at libcore.io.IoBridge.connect(IoBridge.java:122)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:183)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:163)
at java.net.Socket.startupSocket(Socket.java:592)
at java.net.Socket.tryAllAddresses(Socket.java:128)
at java.net.Socket.<init>(Socket.java:178)
at java.net.Socket.<init>(Socket.java:150)
at com.example.admirmonteiro.client.MainActivity$1.onClick(MainActivity.java:70)
at android.view.View.performClick(View.java:5204)
at android.view.View$PerformClick.run(View.java:21153)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

Solution

  • You can't make a toast from a BG thread, unless that thread has called Looper.prepare(). The idea of an AsyncTask is that you perform the long running operation in doInBackground() and then update your UI in onPostExecute(). Move your Toast.makeText() to onPostExecute().

    If you need to debug onPostExecute(), use Log not Toast.