From d11af7ba65fa96b4f7f5bac5e69a985cf06c54f3 Mon Sep 17 00:00:00 2001 From: Aditya-Sood Date: Sat, 3 Aug 2019 21:01:14 +0530 Subject: [PATCH] Major Refactor! - Shift all async-tasks and file transfer code to WDM from LocalFileTransferActivity - LocalFileTransferActivity only deals with setting up the UI now --- .../LocalFileTransferActivity.java | 167 +-------------- .../PeerGroupHandshakeAsyncTask.java | 34 ++- .../ReceiverDeviceAsyncTask.java | 20 +- .../SenderDeviceAsyncTask.java | 28 ++- .../WifiDirectManager.java | 196 +++++++++++++++++- .../WifiPeerListAdapter.java | 2 +- 6 files changed, 244 insertions(+), 203 deletions(-) diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/LocalFileTransferActivity.java b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/LocalFileTransferActivity.java index 8e8dfa17e..0dea3c408 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/LocalFileTransferActivity.java +++ b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/LocalFileTransferActivity.java @@ -9,7 +9,6 @@ import android.location.LocationManager; import android.net.Uri; import android.net.wifi.p2p.WifiP2pDevice; import android.net.wifi.p2p.WifiP2pDeviceList; -import android.net.wifi.p2p.WifiP2pInfo; import android.os.Build; import android.os.Bundle; import android.provider.Settings; @@ -34,14 +33,10 @@ import androidx.recyclerview.widget.RecyclerView; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnItemClick; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.net.InetAddress; import java.util.List; import kotlin.Unit; import kotlin.jvm.functions.Function0; -import org.kiwix.kiwixmobile.BuildConfig; import org.kiwix.kiwixmobile.KiwixApplication; import org.kiwix.kiwixmobile.R; import org.kiwix.kiwixmobile.utils.AlertDialogShower; @@ -53,6 +48,8 @@ import java.util.ArrayList; import javax.inject.Inject; import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.FileItem.FileStatus.TO_BE_SENT; +import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.WifiDirectManager.getDeviceStatus; +import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.WifiDirectManager.getFileName; /** * Created by @Aditya-Sood as a part of GSoC 2019. @@ -92,20 +89,12 @@ public class LocalFileTransferActivity extends AppCompatActivity implements public @NonNull WifiDirectManager wifiDirectManager = new WifiDirectManager(this); - private int totalFilesForTransfer = -1; - private int filesSent = 0; // Count of number of files transferred until now private ArrayList filesToSend = new ArrayList<>(); private FileListAdapter fileListAdapter; private List peerDevices = new ArrayList(); - private InetAddress selectedPeerDeviceInetAddress; - private InetAddress fileReceiverDeviceAddress; // IP address of the file receiving device private boolean fileTransferStarted = false; - private PeerGroupHandshakeAsyncTask peerGroupHandshakeAsyncTask; - private SenderDeviceAsyncTask senderDeviceAsyncTaskArray; - private ReceiverDeviceAsyncTask receiverDeviceAsyncTask; - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { KiwixApplication.getApplicationComponent().activityComponent() @@ -137,19 +126,17 @@ public class LocalFileTransferActivity extends AppCompatActivity implements } }); - wifiDirectManager.createWifiDirectManager(alertDialogShower); + wifiDirectManager.createWifiDirectManager(sharedPreferenceUtil, alertDialogShower, fileUriArrayList); listViewPeerDevices.setAdapter( new WifiPeerListAdapter(this, R.layout.row_peer_device, peerDevices)); if (isFileSender) { - totalFilesForTransfer = fileUriArrayList.size(); - for (int i = 0; i < fileUriArrayList.size(); i++) { filesToSend.add(new FileItem(getFileName(fileUriArrayList.get(i)), TO_BE_SENT)); } - displayFileTransferProgress(); + displayFileTransferProgress(filesToSend); } } @@ -205,14 +192,6 @@ public class LocalFileTransferActivity extends AppCompatActivity implements } /* Helper methods used in the activity */ - public boolean isFileSender() { - return isFileSender; - } - - public @NonNull ArrayList getFileUriArrayList() { - return fileUriArrayList; - } - public void updateUserDevice(@Nullable WifiP2pDevice userDevice) { // Update UI with user device's details wifiDirectManager.setUserDevice(userDevice); @@ -227,33 +206,11 @@ public class LocalFileTransferActivity extends AppCompatActivity implements ((WifiPeerListAdapter) listViewPeerDevices.getAdapter()).notifyDataSetChanged(); } - public static @NonNull String getDeviceStatus(int status) { - - if (BuildConfig.DEBUG) Log.d(TAG, "Peer Status: " + status); - switch (status) { - case WifiP2pDevice.AVAILABLE: - return "Available"; - case WifiP2pDevice.INVITED: - return "Invited"; - case WifiP2pDevice.CONNECTED: - return "Connected"; - case WifiP2pDevice.FAILED: - return "Failed"; - case WifiP2pDevice.UNAVAILABLE: - return "Unavailable"; - - default: - return "Unknown"; + @Override + public void displayFileTransferProgress(ArrayList filesToSend) { + if(!isFileSender) { + this.filesToSend = filesToSend; } - } - - public static @NonNull String getFileName(@NonNull Uri fileUri) { - String fileUriString = fileUri.toString(); - // Returns text after location of last slash in the file path - return fileUriString.substring(fileUriString.lastIndexOf('/') + 1); - } - - private void displayFileTransferProgress() { fileListAdapter = new FileListAdapter(filesToSend); filesRecyclerView.setAdapter(fileListAdapter); filesRecyclerView.setLayoutManager(new LinearLayoutManager(this)); @@ -265,92 +222,6 @@ public class LocalFileTransferActivity extends AppCompatActivity implements textViewPeerDevices.setVisibility(View.INVISIBLE); } - public void setClientAddress(@Nullable InetAddress clientAddress) { - if (clientAddress == null) { - // null is returned only in case of a failed handshake - showToast(this, R.string.device_not_cooperating, Toast.LENGTH_LONG); - finish(); - return; - } - - // If control reaches here, means handshake was successful - selectedPeerDeviceInetAddress = clientAddress; - startFileTransfer(); - } - - private void startFileTransfer() { - fileTransferStarted = true; - - if (wifiDirectManager.isGroupFormed() && !isFileSender) { - displayFileTransferProgress(); - - receiverDeviceAsyncTask = new ReceiverDeviceAsyncTask(this); - receiverDeviceAsyncTask.execute(); - } else if (wifiDirectManager.isGroupFormed()) { // && isFileSender - { - Log.d(LocalFileTransferActivity.TAG, "Starting file transfer"); - - fileReceiverDeviceAddress = - (wifiDirectManager.isGroupOwner()) ? selectedPeerDeviceInetAddress - : wifiDirectManager.getGroupOwnerAddress(); - - // Hack for allowing slower receiver devices to setup server before sender device requests to connect - showToast(this, R.string.preparing_files, Toast.LENGTH_LONG); - for (int i = 0; i < 20000000; i++) ; - - senderDeviceAsyncTaskArray = new SenderDeviceAsyncTask(this); - senderDeviceAsyncTaskArray.execute(fileUriArrayList.toArray(new Uri[0])); - } - } - } - - public int getTotalFilesForTransfer() { - return totalFilesForTransfer; - } - - public void setTotalFilesForTransfer(int totalFilesForTransfer) { - this.totalFilesForTransfer = totalFilesForTransfer; - } - - public @NonNull ArrayList getFileItems() { - return filesToSend; - } - - public void setFileItems(@NonNull ArrayList fileItems) { - this.filesToSend = fileItems; - } - - public void incrementTotalFilesSent() { - this.filesSent++; - } - - public boolean allFilesSent() { - return (filesSent == totalFilesForTransfer); - } - - public @NonNull String getZimStorageRootPath() { - return (sharedPreferenceUtil.getPrefStorage() + "/Kiwix/"); - } - - public @NonNull InetAddress getFileReceiverDeviceAddress() { - return fileReceiverDeviceAddress; - } - - public static void copyToOutputStream(@NonNull InputStream inputStream, @NonNull OutputStream outputStream) - throws IOException { - byte[] bufferForBytes = new byte[1024]; - int bytesRead; - - Log.d(TAG, "Copying to OutputStream..."); - while ((bytesRead = inputStream.read(bufferForBytes)) != -1) { - outputStream.write(bufferForBytes, 0, bytesRead); - } - - outputStream.close(); - inputStream.close(); - Log.d(LocalFileTransferActivity.TAG, "Both streams closed"); - } - public void changeStatus(int itemIndex, @FileItem.FileStatus int status) { filesToSend.get(itemIndex).setFileStatus(status); fileListAdapter.notifyItemChanged(itemIndex); @@ -371,15 +242,6 @@ public class LocalFileTransferActivity extends AppCompatActivity implements } } - @Override - public void performHandshakeWithSelectedPeerDevice(@NonNull WifiP2pInfo groupInfo) { - if (BuildConfig.DEBUG) { - Log.d(TAG, "Starting handshake"); - } - peerGroupHandshakeAsyncTask = new PeerGroupHandshakeAsyncTask(this, groupInfo); - peerGroupHandshakeAsyncTask.execute(); - } - /* Helper methods used for checking permissions and states of services */ private boolean checkCoarseLocationAccessPermission() { // Required by Android to detect wifi-p2p peers if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) @@ -547,19 +409,6 @@ public class LocalFileTransferActivity extends AppCompatActivity implements Toast.makeText(context, text, duration).show(); } - void cancelAsyncTasks() { - if (peerGroupHandshakeAsyncTask != null) { - peerGroupHandshakeAsyncTask.cancel(true); - } - - if (senderDeviceAsyncTaskArray != null) { - senderDeviceAsyncTaskArray.cancel(true); - - } else if (receiverDeviceAsyncTask != null) { - receiverDeviceAsyncTask.cancel(true); - } - } - @Override public void onResume() { super.onResume(); diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/PeerGroupHandshakeAsyncTask.java b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/PeerGroupHandshakeAsyncTask.java index 87e8c3673..259af315c 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/PeerGroupHandshakeAsyncTask.java +++ b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/PeerGroupHandshakeAsyncTask.java @@ -19,7 +19,7 @@ import java.net.Socket; import java.util.ArrayList; import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.FileItem.FileStatus.TO_BE_SENT; -import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.LocalFileTransferActivity.getFileName; +import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.WifiDirectManager.getFileName; /** * Helper class for the local file sharing module. @@ -40,12 +40,10 @@ class PeerGroupHandshakeAsyncTask extends AsyncTask { private static int PEER_HANDSHAKE_PORT = 8009; private final String HANDSHAKE_MESSAGE = "Request Kiwix File Sharing"; - private WeakReference weakReferenceToActivity; - private WifiP2pInfo groupInfo; + private WifiDirectManager wifiDirectManager; - public PeerGroupHandshakeAsyncTask(LocalFileTransferActivity localFileTransferActivity, WifiP2pInfo groupInfo) { - this.weakReferenceToActivity = new WeakReference<>(localFileTransferActivity); - this.groupInfo = groupInfo; + public PeerGroupHandshakeAsyncTask(WifiDirectManager wifiDirectManager) { + this.wifiDirectManager = wifiDirectManager; } @Override @@ -54,7 +52,7 @@ class PeerGroupHandshakeAsyncTask extends AsyncTask { Log.d(TAG, "Handshake in progress"); } - if (groupInfo.groupFormed && groupInfo.isGroupOwner && !isCancelled()) { + if (wifiDirectManager.isGroupFormed() && wifiDirectManager.isGroupOwner() && !isCancelled()) { try (ServerSocket serverSocket = new ServerSocket(PEER_HANDSHAKE_PORT)) { serverSocket.setReuseAddress(true); Socket server = serverSocket.accept(); @@ -77,10 +75,10 @@ class PeerGroupHandshakeAsyncTask extends AsyncTask { ex.printStackTrace(); return null; } - } else if (groupInfo.groupFormed && !isCancelled()) { //&& !groupInfo.isGroupOwner + } else if (wifiDirectManager.isGroupFormed() && !isCancelled()) { //&& !groupInfo.isGroupOwner try (Socket client = new Socket()) { client.setReuseAddress(true); - client.connect((new InetSocketAddress(groupInfo.groupOwnerAddress.getHostAddress(), + client.connect((new InetSocketAddress(wifiDirectManager.getGroupOwnerAddress().getHostAddress(), PEER_HANDSHAKE_PORT)), 15000); ObjectOutputStream objectOutputStream = new ObjectOutputStream(client.getOutputStream()); @@ -89,7 +87,7 @@ class PeerGroupHandshakeAsyncTask extends AsyncTask { exchangeFileTransferMetadata(client.getOutputStream(), client.getInputStream()); - return groupInfo.groupOwnerAddress; + return wifiDirectManager.getGroupOwnerAddress(); } catch (Exception ex) { ex.printStackTrace(); return null; @@ -104,14 +102,13 @@ class PeerGroupHandshakeAsyncTask extends AsyncTask { } private void exchangeFileTransferMetadata(OutputStream outputStream, InputStream inputStream) { - final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get(); - if (localFileTransferActivity.isFileSender()) { + if (wifiDirectManager.isFileSender()) { try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream)) { // Send total number of files which will be transferred - objectOutputStream.writeObject("" + localFileTransferActivity.getTotalFilesForTransfer()); + objectOutputStream.writeObject("" + wifiDirectManager.getTotalFilesForTransfer()); - ArrayList fileUriList = localFileTransferActivity.getFileUriArrayList(); + ArrayList fileUriList = wifiDirectManager.getFileUriArrayList(); for ( Uri fileUri : fileUriList) { // Send the names of each of those files, in order objectOutputStream.writeObject(getFileName(fileUri)); @@ -127,7 +124,8 @@ class PeerGroupHandshakeAsyncTask extends AsyncTask { if (totalFilesObject.getClass().equals(String.class)) { int total = Integer.parseInt((String) totalFilesObject); - localFileTransferActivity.setTotalFilesForTransfer(total); + wifiDirectManager.setTotalFilesForTransfer(total); + if (BuildConfig.DEBUG) Log.d(TAG, "Metadata: "+total+" files"); ArrayList fileItems = new ArrayList<>(); for (int i = 0; i < total; i++) { // Read names of each of those files, in order @@ -135,10 +133,11 @@ class PeerGroupHandshakeAsyncTask extends AsyncTask { if (fileNameObject.getClass().equals(String.class)) { fileItems.add(new FileItem((String) fileNameObject, TO_BE_SENT)); + if (BuildConfig.DEBUG) Log.d(TAG, "Expecting "+fileNameObject); } } - localFileTransferActivity.setFileItems(fileItems); + wifiDirectManager.setFileItems(fileItems); } } catch (Exception e) { e.printStackTrace(); @@ -152,7 +151,6 @@ class PeerGroupHandshakeAsyncTask extends AsyncTask { @Override protected void onPostExecute(InetAddress inetAddress) { - final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get(); - localFileTransferActivity.setClientAddress(inetAddress); + wifiDirectManager.setClientAddress(inetAddress); } } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/ReceiverDeviceAsyncTask.java b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/ReceiverDeviceAsyncTask.java index f5ca691a2..e82cac97f 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/ReceiverDeviceAsyncTask.java +++ b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/ReceiverDeviceAsyncTask.java @@ -19,7 +19,7 @@ import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.FileItem.Fil import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.FileItem.FileStatus.SENDING; import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.FileItem.FileStatus.SENT; import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.WifiDirectManager.FILE_TRANSFER_PORT; -import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.LocalFileTransferActivity.copyToOutputStream; +import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.WifiDirectManager.copyToOutputStream; import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.LocalFileTransferActivity.showToast; /** @@ -38,6 +38,7 @@ class ReceiverDeviceAsyncTask extends AsyncTask { private WeakReference weakReferenceToActivity; private int fileItemIndex; + private String incomingFileName; public ReceiverDeviceAsyncTask(LocalFileTransferActivity localFileTransferActivity) { this.weakReferenceToActivity = new WeakReference<>(localFileTransferActivity); @@ -49,14 +50,16 @@ class ReceiverDeviceAsyncTask extends AsyncTask { if (BuildConfig.DEBUG) Log.d(TAG, "Server: Socket opened at " + FILE_TRANSFER_PORT); final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get(); - final String KIWIX_ROOT = localFileTransferActivity.getZimStorageRootPath(); - int totalFileCount = localFileTransferActivity.getTotalFilesForTransfer(); + final String KIWIX_ROOT = localFileTransferActivity.wifiDirectManager.getZimStorageRootPath(); + int totalFileCount = localFileTransferActivity.wifiDirectManager.getTotalFilesForTransfer(); boolean result = true; + if (BuildConfig.DEBUG) Log.d(TAG, "Expecting "+totalFileCount+" files"); + for (int currentFile = 1; currentFile <= totalFileCount && !isCancelled(); currentFile++) { fileItemIndex = currentFile - 1; - ArrayList fileItems = localFileTransferActivity.getFileItems(); - String incomingFileName = fileItems.get(fileItemIndex).getFileName(); + ArrayList fileItems = localFileTransferActivity.wifiDirectManager.getFileItems(); + incomingFileName = fileItems.get(fileItemIndex).getFileName(); try (Socket client = serverSocket.accept()) { if (BuildConfig.DEBUG) Log.d(TAG, "Server: Client connected for file " + currentFile); @@ -79,11 +82,10 @@ class ReceiverDeviceAsyncTask extends AsyncTask { } catch (IOException e) { Log.e(TAG, e.getMessage()); result = false; - showToast(localFileTransferActivity, localFileTransferActivity.getString(R.string.error_transferring, incomingFileName), Toast.LENGTH_SHORT); publishProgress(fileItemIndex, ERROR); } - localFileTransferActivity.incrementTotalFilesSent(); + localFileTransferActivity.wifiDirectManager.incrementTotalFilesSent(); } return (!isCancelled() && result); @@ -100,6 +102,10 @@ class ReceiverDeviceAsyncTask extends AsyncTask { int fileStatus = values[1]; final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get(); localFileTransferActivity.changeStatus(fileIndex, fileStatus); + + if(fileStatus == ERROR) { + showToast(localFileTransferActivity, localFileTransferActivity.getString(R.string.error_transferring, incomingFileName), Toast.LENGTH_SHORT); + } } @Override protected void onCancelled() { diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/SenderDeviceAsyncTask.java b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/SenderDeviceAsyncTask.java index f24736779..9692d1397 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/SenderDeviceAsyncTask.java +++ b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/SenderDeviceAsyncTask.java @@ -18,8 +18,8 @@ import java.net.Socket; import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.FileItem.FileStatus.*; import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.WifiDirectManager.FILE_TRANSFER_PORT; -import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.LocalFileTransferActivity.copyToOutputStream; -import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.LocalFileTransferActivity.getFileName; +import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.WifiDirectManager.copyToOutputStream; +import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.WifiDirectManager.getFileName; import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.LocalFileTransferActivity.showToast; /** @@ -47,6 +47,16 @@ class SenderDeviceAsyncTask extends AsyncTask { @Override protected Boolean doInBackground(Uri... fileUris) { + + /*try { + Thread.sleep(5000); + } catch (InterruptedException e) { + Log.e(TAG, e.getMessage()); + return false; + }*/ + + for(int i = 0; i < 2000000000; i++); + final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get(); ContentResolver contentResolver = localFileTransferActivity.getContentResolver(); @@ -64,7 +74,7 @@ class SenderDeviceAsyncTask extends AsyncTask { } socket.bind(null); - String hostAddress = localFileTransferActivity.getFileReceiverDeviceAddress().getHostAddress(); + String hostAddress = localFileTransferActivity.wifiDirectManager.getFileReceiverDeviceAddress().getHostAddress(); socket.connect((new InetSocketAddress(hostAddress, FILE_TRANSFER_PORT)), 15000); if (BuildConfig.DEBUG) Log.d(TAG, "Sender socket - " + socket.isConnected()); @@ -79,12 +89,12 @@ class SenderDeviceAsyncTask extends AsyncTask { } catch (IOException e) { Log.e(TAG, e.getMessage()); + e.printStackTrace(); result = false; - showToast(localFileTransferActivity, localFileTransferActivity.getString(R.string.error_transferring, getFileName(localFileTransferActivity.getFileUriArrayList().get(fileItemIndex))), Toast.LENGTH_SHORT); publishProgress(fileItemIndex, ERROR); - } - localFileTransferActivity.incrementTotalFilesSent(); + + localFileTransferActivity.wifiDirectManager.incrementTotalFilesSent(); } return result; @@ -96,6 +106,10 @@ class SenderDeviceAsyncTask extends AsyncTask { int fileStatus = values[1]; final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get(); localFileTransferActivity.changeStatus(fileIndex, fileStatus); + + if(fileStatus == ERROR) { + showToast(localFileTransferActivity, localFileTransferActivity.getString(R.string.error_transferring, getFileName(localFileTransferActivity.wifiDirectManager.getFileUriArrayList().get(fileItemIndex))), Toast.LENGTH_SHORT); + } } @Override protected void onCancelled() { @@ -106,7 +120,7 @@ class SenderDeviceAsyncTask extends AsyncTask { protected void onPostExecute(Boolean fileSendSuccessful) { final LocalFileTransferActivity localFileTransferActivity = weakReferenceToActivity.get(); - if (localFileTransferActivity.allFilesSent()) { + if (localFileTransferActivity.wifiDirectManager.allFilesSent()) { showToast(localFileTransferActivity, R.string.file_transfer_complete, Toast.LENGTH_SHORT); localFileTransferActivity.finish(); diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/WifiDirectManager.java b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/WifiDirectManager.java index dc13a7de4..618f4cf1b 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/WifiDirectManager.java +++ b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/WifiDirectManager.java @@ -3,6 +3,7 @@ package org.kiwix.kiwixmobile.zim_manager.local_file_transfer; import android.content.BroadcastReceiver; import android.content.Context; import android.content.IntentFilter; +import android.net.Uri; import android.net.wifi.WpsInfo; import android.net.wifi.p2p.WifiP2pConfig; import android.net.wifi.p2p.WifiP2pDevice; @@ -14,14 +15,21 @@ import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.InetAddress; +import java.util.ArrayList; import kotlin.Unit; import kotlin.jvm.functions.Function0; +import org.kiwix.kiwixmobile.BuildConfig; import org.kiwix.kiwixmobile.R; import org.kiwix.kiwixmobile.utils.AlertDialogShower; import org.kiwix.kiwixmobile.utils.KiwixDialog; +import org.kiwix.kiwixmobile.utils.SharedPreferenceUtil; import static android.os.Looper.getMainLooper; +import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.FileItem.FileStatus.TO_BE_SENT; import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.LocalFileTransferActivity.showToast; @@ -36,6 +44,9 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2 @NonNull LocalFileTransferActivity activity; + private SharedPreferenceUtil sharedPreferenceUtil; + private AlertDialogShower alertDialogShower; + /* Variables related to the WiFi P2P API */ private boolean wifiP2pEnabled = false; // Whether WiFi has been enabled or not private boolean retryChannel = false; // Whether channel has retried connecting previously @@ -50,15 +61,40 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2 private WifiP2pInfo groupInfo; // Corresponds to P2P group formed between the two devices private WifiP2pDevice senderSelectedPeerDevice = null; - private AlertDialogShower alertDialogShower; + + private PeerGroupHandshakeAsyncTask peerGroupHandshakeAsyncTask; + private SenderDeviceAsyncTask senderDeviceAsyncTaskArray; + private ReceiverDeviceAsyncTask receiverDeviceAsyncTask; + + private boolean isFileTransferInProgress = false; + private InetAddress selectedPeerDeviceInetAddress; + private InetAddress fileReceiverDeviceAddress; // IP address of the file receiving device + + private int totalFilesForTransfer = -1; + private int filesSent = 0; // Count of number of files transferred until now + private ArrayList filesToSend = new ArrayList<>(); + + private ArrayList fileUriArrayList; // For sender device, stores uris of the files + public boolean isFileSender = false; // Whether the device is the file sender or not public WifiDirectManager(@NonNull LocalFileTransferActivity activity) { this.activity = activity; } /* Initialisations for using the WiFi P2P API */ - public void createWifiDirectManager(@NonNull AlertDialogShower alertDialogShower) { + public void createWifiDirectManager(@NonNull SharedPreferenceUtil sharedPreferenceUtil, + @NonNull AlertDialogShower alertDialogShower, @Nullable ArrayList fileUriArrayList) { + this.sharedPreferenceUtil = sharedPreferenceUtil; this.alertDialogShower = alertDialogShower; + this.fileUriArrayList = fileUriArrayList; + this.isFileSender = (fileUriArrayList != null && fileUriArrayList.size() > 0); + + if(isFileSender) { + this.totalFilesForTransfer = fileUriArrayList.size(); + for (int i = 0; i < fileUriArrayList.size(); i++) { + filesToSend.add(new FileItem(getFileName(fileUriArrayList.get(i)), TO_BE_SENT)); + } + } manager = (WifiP2pManager) activity.getSystemService(Context.WIFI_P2P_SERVICE); channel = manager.initialize(activity, getMainLooper(), null); @@ -149,18 +185,14 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2 @Override public void onConnectionInfoAvailable(@NonNull WifiP2pInfo groupInfo) { /* Devices have successfully connected, and 'info' holds information about the wifi p2p group formed */ - setGroupInfo(groupInfo); - ((Callbacks) activity).performHandshakeWithSelectedPeerDevice(groupInfo); + this.groupInfo = groupInfo; + performHandshakeWithSelectedPeerDevice(); } public void setUserDevice(@NonNull WifiP2pDevice userDevice) { this.userDevice = userDevice; } - public void setGroupInfo(@NonNull WifiP2pInfo groupInfo) { - this.groupInfo = groupInfo; - } - public boolean isGroupFormed() { return groupInfo.groupFormed; } @@ -212,11 +244,127 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2 }); } + public void performHandshakeWithSelectedPeerDevice() { + if (BuildConfig.DEBUG) { + Log.d(TAG, "Starting handshake"); + } + peerGroupHandshakeAsyncTask = new PeerGroupHandshakeAsyncTask(this); + peerGroupHandshakeAsyncTask.execute(); + } + + public boolean isFileSender() { + return isFileSender; + } + + public @NonNull ArrayList getFileUriArrayList() { + return fileUriArrayList; + } + + public int getTotalFilesForTransfer() { + return totalFilesForTransfer; + } + + public void setTotalFilesForTransfer(int totalFilesForTransfer) { + this.totalFilesForTransfer = totalFilesForTransfer; + } + + public @NonNull ArrayList getFileItems() { + return filesToSend; + } + + public void setFileItems(@NonNull ArrayList fileItems) { + this.filesToSend = fileItems; + } + + public void incrementTotalFilesSent() { + this.filesSent++; + } + + public boolean allFilesSent() { + return (filesSent == totalFilesForTransfer); + } + + public @NonNull String getZimStorageRootPath() { + return (sharedPreferenceUtil.getPrefStorage() + "/Kiwix/"); + } + + public @NonNull InetAddress getFileReceiverDeviceAddress() { + return fileReceiverDeviceAddress; + } + + public static void copyToOutputStream(@NonNull InputStream inputStream, @NonNull + OutputStream outputStream) + throws IOException { + byte[] bufferForBytes = new byte[1024]; + int bytesRead; + + Log.d(TAG, "Copying to OutputStream..."); + while ((bytesRead = inputStream.read(bufferForBytes)) != -1) { + outputStream.write(bufferForBytes, 0, bytesRead); + } + + outputStream.close(); + inputStream.close(); + Log.d(LocalFileTransferActivity.TAG, "Both streams closed"); + } + + public void setClientAddress(@Nullable InetAddress clientAddress) { + if (clientAddress == null) { + // null is returned only in case of a failed handshake + showToast(activity, R.string.device_not_cooperating, Toast.LENGTH_LONG); + activity.finish(); + return; + } + + // If control reaches here, means handshake was successful + selectedPeerDeviceInetAddress = clientAddress; + startFileTransfer(); + } + + private void startFileTransfer() { + isFileTransferInProgress = true; + + if (isGroupFormed() && !isFileSender) { + ((Callbacks) activity).displayFileTransferProgress(filesToSend); + + receiverDeviceAsyncTask = new ReceiverDeviceAsyncTask(activity); + receiverDeviceAsyncTask.execute(); + } else if (isGroupFormed()) { // && isFileSender + { + Log.d(LocalFileTransferActivity.TAG, "Starting file transfer"); + + fileReceiverDeviceAddress = + (isGroupOwner()) ? selectedPeerDeviceInetAddress + : getGroupOwnerAddress(); + + // Hack for allowing slower receiver devices to setup server before sender device requests to connect + showToast(activity, R.string.preparing_files, Toast.LENGTH_LONG); + //for (int i = 0; i < 20000000; i++) ; + + senderDeviceAsyncTaskArray = new SenderDeviceAsyncTask(activity); + senderDeviceAsyncTaskArray.execute(fileUriArrayList.toArray(new Uri[0])); + } + } + } + + void cancelAsyncTasks() { + if (peerGroupHandshakeAsyncTask != null) { + peerGroupHandshakeAsyncTask.cancel(true); + } + + if (senderDeviceAsyncTaskArray != null) { + senderDeviceAsyncTaskArray.cancel(true); + + } else if (receiverDeviceAsyncTask != null) { + receiverDeviceAsyncTask.cancel(true); + } + } + // TODO: Shift async tasks to WDM and handle cleanup from here itself public void destroyWifiDirectManager() { - activity.cancelAsyncTasks(); + cancelAsyncTasks(); - if (!activity.isFileSender) { + if (!isFileSender) { disconnect(); } else { closeChannel(); @@ -261,9 +409,35 @@ public class WifiDirectManager implements WifiP2pManager.ChannelListener, WifiP2 } } + public static @NonNull String getDeviceStatus(int status) { + + if (BuildConfig.DEBUG) Log.d(TAG, "Peer Status: " + status); + switch (status) { + case WifiP2pDevice.AVAILABLE: + return "Available"; + case WifiP2pDevice.INVITED: + return "Invited"; + case WifiP2pDevice.CONNECTED: + return "Connected"; + case WifiP2pDevice.FAILED: + return "Failed"; + case WifiP2pDevice.UNAVAILABLE: + return "Unavailable"; + + default: + return "Unknown"; + } + } + + public static @NonNull String getFileName(@NonNull Uri fileUri) { + String fileUriString = fileUri.toString(); + // Returns text after location of last slash in the file path + return fileUriString.substring(fileUriString.lastIndexOf('/') + 1); + } + public interface Callbacks { void updatePeerDevicesList(@NonNull WifiP2pDeviceList peers); - void performHandshakeWithSelectedPeerDevice(@NonNull WifiP2pInfo groupInfo); + void displayFileTransferProgress(ArrayList filesToSend); } } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/WifiPeerListAdapter.java b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/WifiPeerListAdapter.java index b3f7b8fc4..922501c39 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/WifiPeerListAdapter.java +++ b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/local_file_transfer/WifiPeerListAdapter.java @@ -17,7 +17,7 @@ import org.kiwix.kiwixmobile.R; import java.util.List; -import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.LocalFileTransferActivity.getDeviceStatus; +import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.WifiDirectManager.getDeviceStatus; /** * Helper class, part of the local file sharing module.