/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.commcare.android.framework; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import org.commcare.android.javarosa.AndroidLogger; import org.commcare.android.util.FileUtil; import org.commcare.dalvik.R; import org.commcare.dalvik.activities.CommCareWiFiDirectActivity; import org.javarosa.core.services.Logger; import android.annotation.SuppressLint; import android.app.Activity; import android.app.ProgressDialog; import android.os.AsyncTask; import android.os.AsyncTask.Status; 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; /** * 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 { protected static final int CHOOSE_FILE_RESULT_CODE = 20; private View mContentView = null; ProgressDialog progressDialog = null; private static CommCareWiFiDirectActivity mActivity; private static TextView mStatusText; private View mView; public static String receiveZipDirectory; private FileServerAsyncTask mFileServer; /* * (non-Javadoc) * @see android.support.v4.app.Fragment#onActivityCreated(android.os.Bundle) */ @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } /* * (non-Javadoc) * @see android.support.v4.app.Fragment#onAttach(android.app.Activity) */ @Override public void onAttach(Activity activity){ super.onAttach(activity); try { mActivity = (CommCareWiFiDirectActivity) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement fileServerListener"); } } /* * (non-Javadoc) * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle) */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mContentView = inflater.inflate(R.layout.file_server, null); mStatusText = (TextView)mContentView.findViewById(R.id.file_server_status_text); mView = (View)mContentView.findViewById(R.id.file_server_view); return mContentView; } public interface FileServerListener{ public void onFormsCopied(String result); } public void startServer(String mReceiveZipDirectory){ Logger.log(CommCareWiFiDirectActivity.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 FileServerFragment mListener; private boolean socketOccupied; /** * @param context * @param statusText */ public FileServerAsyncTask(FileServerFragment mListener) { Log.d(CommCareWiFiDirectActivity.TAG, "new fileasync task"); this.mListener = mListener; } /* * (non-Javadoc) * @see android.os.AsyncTask#doInBackground(java.lang.Object[]) */ @Override protected String doInBackground(Void... params) { Logger.log(CommCareWiFiDirectActivity.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(CommCareWiFiDirectActivity.TAG, "Ready in wi-fi direct file server receive loop"); Log.d(CommCareWiFiDirectActivity.TAG, "server: copying files " + finalFileName); final File f = new File(finalFileName); File dirs = new File(f.getParent()); dirs.mkdirs(); f.createNewFile(); Log.d(CommCareWiFiDirectActivity.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(CommCareWiFiDirectActivity.TAG, e.getMessage()); final File f = new File(finalFileName); if(f.exists()){ FileUtil.deleteFile(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(CommCareWiFiDirectActivity.TAG, "couldn't open socket!"); socketOccupied = true; return null; } } /* * (non-Javadoc) * @see android.os.AsyncTask#onPostExecute(java.lang.Object) */ @Override protected void onPostExecute(String result) { Log.e(CommCareWiFiDirectActivity.TAG, "file server task post execute"); if(socketOccupied){ Logger.log(CommCareWiFiDirectActivity.TAG, "socket busy, cancelling this thread cycle"); return; } if(result != null){ mActivity.onFormsCopied(result); } Logger.log(CommCareWiFiDirectActivity.TAG, "file server post-execute, relaunching server"); mListener.startServer(receiveZipDirectory); } /* * (non-Javadoc) * @see android.os.AsyncTask#onPreExecute() */ @Override protected void onPreExecute() { Logger.log(CommCareWiFiDirectActivity.TAG, "pre-execute of file server launch"); // statusText.setText("Opening a server socket"); } /* * (non-Javadoc) * @see android.os.AsyncTask#onPreExecute() */ @Override protected void onProgressUpdate(String ... params){ mStatusText.setText(params[0]); } } }