package org.commcare.fragments; import android.annotation.SuppressLint; import android.content.Context; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import org.commcare.activities.CommCareWiFiDirectActivity; import org.commcare.dalvik.R; import org.commcare.utils.FileUtil; import org.javarosa.core.services.Logger; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /** * A fragment that manages a particular peer and allows interaction with device * i.e. setting up network connection and transferring data. */ @SuppressLint("NewApi") public class FileServerFragment extends Fragment { private static final String TAG = FileServerFragment.class.getSimpleName(); private static CommCareWiFiDirectActivity mActivity; private static TextView mStatusText; private View mView; private static String receiveZipDirectory; private FileServerAsyncTask mFileServer; @Override public void onAttach(Context context) { super.onAttach(context); try { mActivity = (CommCareWiFiDirectActivity)context; } catch (ClassCastException e) { throw new ClassCastException(context.toString() + " must implement fileServerListener"); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View contentView; contentView = inflater.inflate(R.layout.file_server, null); mStatusText = (TextView)contentView.findViewById(R.id.file_server_status_text); mView = contentView.findViewById(R.id.file_server_view); return contentView; } public interface FileServerListener { void onFormsCopied(String result); } public void startServer(String mReceiveZipDirectory) { Logger.log(TAG, "File Server starting..."); mStatusText.setText("Starting server"); mView.setVisibility(View.VISIBLE); if (mFileServer != null) { mFileServer.cancel(true); } mFileServer = new FileServerAsyncTask(this); receiveZipDirectory = mReceiveZipDirectory; //Execute on a true multithreaded chain. We should probably replace all of our calls with this //but this is the big one for now. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { mFileServer.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { mFileServer.execute(); } } /** * A simple server socket that accepts connection and writes some data on * the stream. */ public static class FileServerAsyncTask extends AsyncTask<Void, String, String> { private final FileServerFragment mListener; private boolean socketOccupied; public FileServerAsyncTask(FileServerFragment mListener) { Log.d(TAG, "new fileasync task"); this.mListener = mListener; } @Override protected String doInBackground(Void... params) { Logger.log(TAG, "doing in background"); socketOccupied = false; try { ServerSocket serverSocket = new ServerSocket(8988); long time = System.currentTimeMillis(); String finalFileName = receiveZipDirectory + time + ".zip"; try { publishProgress("Ready to accept new file transfer.", null); Socket client = serverSocket.accept(); Logger.log(TAG, "Ready in wi-fi direct file server receive loop"); Log.d(TAG, "server: copying files " + finalFileName); final File f = new File(finalFileName); File dirs = new File(f.getParent()); dirs.mkdirs(); f.createNewFile(); Log.d(TAG, "server: copying files " + f.toString()); InputStream inputstream = client.getInputStream(); CommCareWiFiDirectActivity.copyFile(inputstream, new FileOutputStream(f)); serverSocket.close(); publishProgress("copied files: " + f.getAbsolutePath(), f.getAbsolutePath()); publishProgress("File Server Resetting", null); return f.getAbsolutePath(); } catch (IOException e) { Log.e(TAG, e.getMessage()); final File f = new File(finalFileName); if (f.exists()) { FileUtil.deleteFileOrDir(f); } publishProgress("File Server crashed with an IO Exception: " + e.getMessage()); return null; } finally { serverSocket.close(); } } catch (IOException ioe) { publishProgress("Ready to accept new file transfer.", null); Logger.log(TAG, "couldn't open socket!"); socketOccupied = true; return null; } } @Override protected void onPostExecute(String result) { Log.e(TAG, "file server task post execute"); if (socketOccupied) { Logger.log(TAG, "socket busy, cancelling this thread cycle"); return; } if (result != null) { mActivity.onFormsCopied(result); } Logger.log(TAG, "file server post-execute, relaunching server"); mListener.startServer(receiveZipDirectory); } @Override protected void onPreExecute() { Logger.log(TAG, "pre-execute of file server launch"); // statusText.setText("Opening a server socket"); } @Override protected void onProgressUpdate(String... params) { mStatusText.setText(params[0]); } } }