mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-22 12:03:09 -04:00
Increment: LocalFileTransferActivity now has core functionality
The activity can now be used to send one selected ZIM file to a nearby device (Cleanup and refactoring yet to be done)
This commit is contained in:
parent
25e0ef4dd7
commit
e357d47d49
@ -14,6 +14,10 @@
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
|
||||
<application
|
||||
android:name=".KiwixApplication"
|
||||
@ -223,6 +227,7 @@
|
||||
-->
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service android:enabled="true" android:name=".zim_manager.local_file_transfer.FileTransferService" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
@ -43,6 +43,7 @@ import org.kiwix.kiwixmobile.base.BaseActivity;
|
||||
import org.kiwix.kiwixmobile.language.LanguageActivity;
|
||||
import org.kiwix.kiwixmobile.main.MainActivity;
|
||||
import org.kiwix.kiwixmobile.models.Language;
|
||||
import org.kiwix.kiwixmobile.zim_manager.local_file_transfer.LocalFileTransferActivity;
|
||||
|
||||
import static org.kiwix.kiwixmobile.utils.Constants.TAG_KIWIX;
|
||||
|
||||
@ -234,6 +235,13 @@ public class ZimManageActivity extends BaseActivity implements ZimManageViewCall
|
||||
showLanguageSelect();
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
|
||||
case R.id.get_zim_nearby_device:
|
||||
Intent localFileTransferIntent = new Intent(this, LocalFileTransferActivity.class);
|
||||
startActivity(localFileTransferIntent);
|
||||
return true;
|
||||
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
@ -0,0 +1,588 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager.local_file_transfer;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.p2p.WifiP2pDevice;
|
||||
import android.net.wifi.p2p.WifiP2pDeviceList;
|
||||
import android.net.wifi.p2p.WifiP2pInfo;
|
||||
import android.net.wifi.p2p.WifiP2pManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.fragment.app.ListFragment;
|
||||
|
||||
import org.kiwix.kiwixmobile.BuildConfig;
|
||||
import org.kiwix.kiwixmobile.R;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.DeviceListFragment.TAG;
|
||||
import static org.kiwix.kiwixmobile.zim_manager.local_file_transfer.LocalFileTransferActivity.filePath;
|
||||
|
||||
public class DeviceListFragment extends ListFragment implements WifiP2pManager.PeerListListener, WifiP2pManager.ConnectionInfoListener, PeerGroupHandshakeAsyncTask.ClientAddressReady {
|
||||
|
||||
public static String TAG = "DeviceListFragment";
|
||||
|
||||
private View fragRootView = null;
|
||||
private List<WifiP2pDevice> peerDevices = new ArrayList<WifiP2pDevice>();
|
||||
private WifiP2pDevice userDevice;
|
||||
private WifiP2pDevice selectedPeerDevice = null;
|
||||
private InetAddress selectedPeerDeviceInetAddress;
|
||||
private WifiP2pInfo groupInfo;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
this.setListAdapter(new WifiPeerListAdapter(getActivity(), R.layout.row_peer_device, peerDevices));
|
||||
|
||||
ImageButton editUserDeviceName = getActivity().findViewById(R.id.btn_edit_device_name);
|
||||
editUserDeviceName.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if(userDevice != null) {
|
||||
//TODO: Dialog to take input & call this method:
|
||||
//((DeviceActionListener) getActivity()).changeDeviceName("Sood");
|
||||
|
||||
if(((LocalFileTransferActivity) getActivity()).isWifiP2pEnabled()) {
|
||||
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
|
||||
Fragment prev = getActivity().getSupportFragmentManager().findFragmentByTag("EditDeviceNameDialog");
|
||||
if (prev != null) {
|
||||
fragmentTransaction.remove(prev); // To prevent multiple instances of the DialogFragment
|
||||
}
|
||||
fragmentTransaction.addToBackStack(null);
|
||||
|
||||
EditDeviceNameDialog dialogFragment = new EditDeviceNameDialog();
|
||||
// For DialogFragments, show() handles the fragment commit and display
|
||||
dialogFragment.show(fragmentTransaction, "EditDeviceNameDialog");
|
||||
} else {
|
||||
Toast.makeText(getActivity(), "Enable WiFi P2P to change device name", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
fragRootView = inflater.inflate(R.layout.fragment_device_list, null);
|
||||
return fragRootView;
|
||||
}
|
||||
|
||||
public WifiP2pDevice getUserDevice() { return userDevice; }
|
||||
|
||||
private static String getDeviceStatus(int status) {
|
||||
|
||||
Log.d(LocalFileTransferActivity.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 onListItemClick(ListView l, View v, int position, long id) {
|
||||
selectedPeerDevice = (WifiP2pDevice) getListAdapter().getItem(position);
|
||||
Toast.makeText(getActivity(), selectedPeerDevice.deviceName, Toast.LENGTH_SHORT).show();
|
||||
|
||||
// TODO: Set sender depending upon receiving file URI in activity opening intent
|
||||
//((LocalFileTransferActivity) getActivity()).setFileSender();
|
||||
((DeviceActionListener) getActivity()).connect(selectedPeerDevice);
|
||||
}
|
||||
|
||||
public void updateUserDevice(WifiP2pDevice device) {
|
||||
this.userDevice = device;
|
||||
|
||||
if(userDevice != null) {
|
||||
TextView deviceName = fragRootView.findViewById(R.id.text_view_device_name);
|
||||
TextView deviceStatus = fragRootView.findViewById(R.id.text_view_device_status);
|
||||
|
||||
if(deviceName != null) deviceName.setText(userDevice.deviceName);
|
||||
if(deviceStatus != null) deviceStatus.setText(getDeviceStatus(userDevice.status));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeersAvailable(WifiP2pDeviceList peers) {
|
||||
|
||||
ProgressBar searchingPeersProgressBar = fragRootView.findViewById(R.id.progress_bar_searching_peers);
|
||||
searchingPeersProgressBar.setVisibility(View.GONE);
|
||||
FrameLayout frameLayoutPeerDevices = fragRootView.findViewById(R.id.frame_layout_peer_devices);
|
||||
frameLayoutPeerDevices.setVisibility(View.VISIBLE);
|
||||
|
||||
peerDevices.clear();
|
||||
peerDevices.addAll(peers.getDeviceList());
|
||||
((WifiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
|
||||
|
||||
if(peerDevices.size() == 0) {
|
||||
Log.d(LocalFileTransferActivity.TAG, "No devices found");
|
||||
}
|
||||
}
|
||||
|
||||
public void clearPeers() {
|
||||
peerDevices.clear();
|
||||
((WifiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void onInitiateDiscovery() {
|
||||
ProgressBar searchingPeersProgressBar = fragRootView.findViewById(R.id.progress_bar_searching_peers);
|
||||
searchingPeersProgressBar.setVisibility(View.VISIBLE);
|
||||
FrameLayout frameLayoutPeerDevices = fragRootView.findViewById(R.id.frame_layout_peer_devices);
|
||||
frameLayoutPeerDevices.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionInfoAvailable(WifiP2pInfo info) {
|
||||
groupInfo = info;
|
||||
|
||||
//TODO: Show progress of file transfer process
|
||||
|
||||
new PeerGroupHandshakeAsyncTask(this, groupInfo).execute();
|
||||
|
||||
/*if(groupInfo.groupFormed && groupInfo.isGroupOwner) {
|
||||
|
||||
try {
|
||||
ServerSocket serverSocket = new ServerSocket(8008);
|
||||
serverSocket.setReuseAddress(true);
|
||||
Socket client = serverSocket.accept();
|
||||
ObjectInputStream objectInputStream = new ObjectInputStream(client.getInputStream());
|
||||
Object object = objectInputStream.readObject();
|
||||
if (object.getClass().equals(String.class) && ((String) object).equals("Request Kiwix File Sharing")) {
|
||||
Log.d(TAG, "Client IP address: "+ client.getInetAddress());
|
||||
selectedPeerDeviceInetAddress = client.getInetAddress();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//Log.d(TAG, e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
} else if(groupInfo.groupFormed && !groupInfo.isGroupOwner) {
|
||||
|
||||
try {
|
||||
Socket socket = new Socket();
|
||||
socket.setReuseAddress(true);
|
||||
socket.connect((new InetSocketAddress(groupInfo.groupOwnerAddress.getHostAddress(), 8008)), 15000);
|
||||
OutputStream os = socket.getOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(os);
|
||||
oos.writeObject(new String("Request Kiwix File Sharing"));
|
||||
oos.close();
|
||||
os.close();
|
||||
socket.close();
|
||||
} catch (Exception e) {
|
||||
//Log.d(TAG, e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
*//*Intent serviceIntent = new Intent(getActivity(), FileTransferService.class);
|
||||
serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH, Environment.getExternalStorageDirectory() + "/MainPage.txt");
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS, groupInfo.groupOwnerAddress.getHostAddress());
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8008);
|
||||
getActivity().startService(serviceIntent);*//*
|
||||
}
|
||||
|
||||
if(groupInfo.groupFormed && ((MainActivity) getActivity()).isFileSender()) {
|
||||
Toast.makeText(getActivity(), "Sending file to "+selectedPeerDevice.deviceAddress+"\nSelf: "+userDevice.deviceAddress, Toast.LENGTH_SHORT).show();
|
||||
Log.d(MainActivity.TAG, "Starting file transfer");
|
||||
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setMessage("Transfer file?")
|
||||
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Intent serviceIntent = new Intent(getActivity(), FileTransferService.class);
|
||||
serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH, FileProvider.getUriForFile(getActivity(), BuildConfig.APPLICATION_ID+".fileprovider", new File(filePath)).toString());
|
||||
|
||||
InetAddress fileReceiverAddress;
|
||||
if(groupInfo.isGroupOwner) fileReceiverAddress = selectedPeerDeviceInetAddress;
|
||||
else fileReceiverAddress = groupInfo.groupOwnerAddress;
|
||||
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS, fileReceiverAddress.getHostAddress());//getIPFromMac(selectedPeerDevice.deviceAddress));
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8008);
|
||||
getActivity().startService(serviceIntent);
|
||||
}
|
||||
})
|
||||
.setNegativeButton("No", null)
|
||||
.show();
|
||||
|
||||
|
||||
} else {
|
||||
Toast.makeText(getActivity(), "File receiving device", Toast.LENGTH_SHORT).show();
|
||||
new FileServerAsyncTask(getActivity()).execute();
|
||||
}*/
|
||||
|
||||
// TODO: Disable onclick listener (of list) for connecting to devices
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientAddress(InetAddress clientAddress) {
|
||||
if(clientAddress != null) selectedPeerDeviceInetAddress = clientAddress;
|
||||
|
||||
startFileTransfer();
|
||||
}
|
||||
|
||||
private void startFileTransfer() {
|
||||
if(groupInfo.groupFormed && !((LocalFileTransferActivity) getActivity()).isFileSender()) {
|
||||
Toast.makeText(getActivity(), "File receiving device", Toast.LENGTH_SHORT).show();
|
||||
new FileServerAsyncTask(getActivity()).execute();
|
||||
|
||||
} else if(groupInfo.groupFormed) {
|
||||
{
|
||||
Toast.makeText(getActivity(), "Sending file to "+selectedPeerDevice.deviceAddress+"\nSelf: "+userDevice.deviceAddress, Toast.LENGTH_SHORT).show();
|
||||
Log.d(LocalFileTransferActivity.TAG, "Starting file transfer");
|
||||
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setMessage("Transfer file?")
|
||||
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Intent serviceIntent = new Intent(getActivity(), FileTransferService.class);
|
||||
serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_URI, filePath.toString());//FileProvider.getUriForFile(getActivity(), BuildConfig.APPLICATION_ID+".fileprovider", new File(filePath)).toString());
|
||||
|
||||
InetAddress fileReceiverAddress;
|
||||
if(groupInfo.isGroupOwner) fileReceiverAddress = selectedPeerDeviceInetAddress;
|
||||
else fileReceiverAddress = groupInfo.groupOwnerAddress;
|
||||
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS, fileReceiverAddress.getHostAddress());//getIPFromMac(selectedPeerDevice.deviceAddress));
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8008);
|
||||
getActivity().startService(serviceIntent);
|
||||
}
|
||||
})
|
||||
.setNegativeButton("No", null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class WifiPeerListAdapter extends ArrayAdapter<WifiP2pDevice> {
|
||||
|
||||
private List<WifiP2pDevice> listItems;
|
||||
|
||||
public WifiPeerListAdapter(@NonNull Context context, int resource, List<WifiP2pDevice> objects) {
|
||||
super(context, resource, objects);
|
||||
this.listItems = objects;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
|
||||
View rowView = convertView;
|
||||
if(rowView == null) {
|
||||
LayoutInflater layoutInflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
rowView = layoutInflater.inflate(R.layout.row_peer_device, parent, false);
|
||||
}
|
||||
|
||||
WifiP2pDevice device = listItems.get(position);
|
||||
|
||||
if(device != null) {
|
||||
TextView deviceName = rowView.findViewById(R.id.row_device_name);
|
||||
TextView deviceStatus = rowView.findViewById(R.id.row_device_status);
|
||||
|
||||
if(deviceName != null) deviceName.setText(device.deviceName);
|
||||
if(deviceStatus != null) deviceStatus.setText(getDeviceStatus(device.status));
|
||||
}
|
||||
|
||||
return rowView;
|
||||
}
|
||||
}
|
||||
|
||||
public interface DeviceActionListener {
|
||||
|
||||
void changeDeviceName(String deviceNewName);
|
||||
|
||||
/*void showDetails(WifiP2pDevice device);*/
|
||||
|
||||
void cancelDisconnect();
|
||||
|
||||
void connect(WifiP2pDevice peerDevice);
|
||||
|
||||
void disconnect();
|
||||
}
|
||||
|
||||
//private class EditNameDialog e
|
||||
/*private void requestEnableLocationServices() {
|
||||
|
||||
*//*Toast.makeText(MainActivity.this, "Enable location to allow detection of peers", Toast.LENGTH_LONG);
|
||||
startActivityForResult(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), 1);*//*
|
||||
*//*new AlertDialog.Builder(this)
|
||||
.setMessage("Enable location to allow detection of peers")
|
||||
.setPositiveButton("Open Location Settings", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
|
||||
paramDialogInterface.cancel();
|
||||
startActivityForResult(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), 1);
|
||||
}
|
||||
})
|
||||
.setNegativeButton("No", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
|
||||
}
|
||||
})
|
||||
.show();*//*
|
||||
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
Fragment prev = getSupportFragmentManager().findFragmentByTag("LocationDialog");
|
||||
if(prev != null) {
|
||||
fragmentTransaction.remove(prev); // To prevent multiple instances of the DialogFragment
|
||||
}
|
||||
fragmentTransaction.addToBackStack(null);
|
||||
|
||||
RequestEnableLocationServicesDialog dialogFragment = new RequestEnableLocationServicesDialog();
|
||||
// For DialogFragments, show() handles the fragment commit and display
|
||||
dialogFragment.show(fragmentTransaction, "LocationDialog");
|
||||
|
||||
}
|
||||
|
||||
public static class RequestEnableLocationServicesDialog extends DialogFragment {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setMessage("Enable location to allow detection of peers")
|
||||
.setPositiveButton("Open Location Settings", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
|
||||
paramDialogInterface.cancel();
|
||||
startActivityForResult(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), 1);
|
||||
}
|
||||
})
|
||||
.setNegativeButton("No", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
//TODO: Close activity
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
}*/
|
||||
|
||||
public static class EditDeviceNameDialog extends DialogFragment {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
|
||||
builder.setView(R.layout.dialog_edit_device_name)
|
||||
.setPositiveButton("Update", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
EditText changeDeviceName = EditDeviceNameDialog.this.getDialog().findViewById(R.id.edit_text_change_device_name);
|
||||
String deviceNewName = changeDeviceName.getText().toString();
|
||||
//Toast.makeText(getActivity(), "Changing name to: " + deviceNewName.getText().toString(), Toast.LENGTH_SHORT).show();
|
||||
|
||||
if(deviceNewName != null && !deviceNewName.equals("")) {
|
||||
((DeviceActionListener) getActivity()).changeDeviceName(deviceNewName);
|
||||
} else {
|
||||
Toast.makeText(getActivity(), "Error: Empty name field", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
//dialog.cancel();
|
||||
}
|
||||
})
|
||||
.setNeutralButton("Dismiss", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
|
||||
public static class FileServerAsyncTask extends AsyncTask<Void, Void, String> {
|
||||
|
||||
private Context context;
|
||||
//private View statusView
|
||||
|
||||
public FileServerAsyncTask(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... voids) {
|
||||
try {
|
||||
ServerSocket serverSocket = new ServerSocket(8008);
|
||||
Log.d(LocalFileTransferActivity.TAG, "Server: Socket opened at 8008");
|
||||
Socket client = serverSocket.accept();
|
||||
Log.d(LocalFileTransferActivity.TAG, "Server: Client connected");
|
||||
|
||||
// File selector, file not exists,
|
||||
//TODO: Change to appropriate file-path
|
||||
final File clientNoteFileLocation = new File(Environment.getExternalStorageDirectory() + "/KiwixWifi/temp.zim");
|
||||
File dirs = new File(clientNoteFileLocation.getParent());
|
||||
if(!dirs.exists()) {
|
||||
Log.d(LocalFileTransferActivity.TAG, "Parent creation result: "+dirs.mkdirs());
|
||||
} else {
|
||||
Log.d(LocalFileTransferActivity.TAG, "Parent directories exist");
|
||||
}
|
||||
|
||||
Log.d(LocalFileTransferActivity.TAG, "File creation: "+clientNoteFileLocation.createNewFile());
|
||||
|
||||
Log.d(LocalFileTransferActivity.TAG, "Copying files");
|
||||
InputStream inputStream = client.getInputStream();
|
||||
copyFile(inputStream, new FileOutputStream(clientNoteFileLocation));
|
||||
serverSocket.close();
|
||||
return clientNoteFileLocation.getAbsolutePath();
|
||||
|
||||
} catch (IOException e) {
|
||||
Log.e(LocalFileTransferActivity.TAG, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String s) {
|
||||
super.onPostExecute(s);
|
||||
Toast.makeText(context, "File transfer complete", Toast.LENGTH_LONG).show();
|
||||
Log.d(LocalFileTransferActivity.TAG, "File transfer complete");
|
||||
|
||||
/*File recvFile = new File(filePath);
|
||||
Uri fileUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID+".fileprovider",recvFile);
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(fileUri, "text/plain");
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
context.startActivity(intent);*/
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean copyFile(InputStream inputStream, OutputStream out) {
|
||||
byte buf[] = new byte[1024];
|
||||
int len;
|
||||
try {
|
||||
while ((len = inputStream.read(buf)) != -1) {
|
||||
out.write(buf, 0, len);
|
||||
|
||||
}
|
||||
out.close();
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.d(LocalFileTransferActivity.TAG, e.toString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class PeerGroupHandshakeAsyncTask extends AsyncTask<Void, Void, InetAddress> {
|
||||
|
||||
private DeviceListFragment deviceListFragment;
|
||||
private WifiP2pInfo groupInfo;
|
||||
|
||||
public PeerGroupHandshakeAsyncTask(DeviceListFragment deviceListFragment, WifiP2pInfo groupInfo) {
|
||||
this.deviceListFragment = deviceListFragment;
|
||||
this.groupInfo = groupInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InetAddress doInBackground(Void... voids) {
|
||||
if(groupInfo.groupFormed && groupInfo.isGroupOwner) {
|
||||
|
||||
try {
|
||||
ServerSocket serverSocket = new ServerSocket(8009);
|
||||
serverSocket.setReuseAddress(true);
|
||||
Socket client = serverSocket.accept();
|
||||
ObjectInputStream objectInputStream = new ObjectInputStream(client.getInputStream());
|
||||
Object object = objectInputStream.readObject();
|
||||
if (object.getClass().equals(String.class) && ((String) object).equals("Request Kiwix File Sharing")) {
|
||||
Log.d(TAG, "Client IP address: "+ client.getInetAddress());
|
||||
//selectedPeerDeviceInetAddress = client.getInetAddress();
|
||||
}
|
||||
return client.getInetAddress();
|
||||
} catch (Exception e) {
|
||||
//Log.d(TAG, e.getMessage());
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
} else if(groupInfo.groupFormed && !groupInfo.isGroupOwner) {
|
||||
|
||||
try {
|
||||
Socket socket = new Socket();
|
||||
socket.setReuseAddress(true);
|
||||
for(int i = 0; i < 100000000; i++);
|
||||
socket.connect((new InetSocketAddress(groupInfo.groupOwnerAddress.getHostAddress(), 8009)), 15000);
|
||||
OutputStream os = socket.getOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(os);
|
||||
oos.writeObject(new String("Request Kiwix File Sharing"));
|
||||
oos.close();
|
||||
os.close();
|
||||
socket.close();
|
||||
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
//Log.d(TAG, e.getMessage());
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
/*Intent serviceIntent = new Intent(getActivity(), FileTransferService.class);
|
||||
serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH, Environment.getExternalStorageDirectory() + "/MainPage.txt");
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS, groupInfo.groupOwnerAddress.getHostAddress());
|
||||
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8008);
|
||||
getActivity().startService(serviceIntent);*/
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(InetAddress inetAddress) {
|
||||
(deviceListFragment).setClientAddress(inetAddress);
|
||||
}
|
||||
|
||||
public interface ClientAddressReady {
|
||||
void setClientAddress(InetAddress clientAddress);
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
|
||||
package org.kiwix.kiwixmobile.zim_manager.local_file_transfer;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* A service that process each file transfer request i.e Intent by opening a
|
||||
* socket connection with the WiFi Direct Group Owner and writing the file
|
||||
*/
|
||||
public class FileTransferService extends IntentService {
|
||||
|
||||
private static final int SOCKET_TIMEOUT = 15000;
|
||||
public static final String ACTION_SEND_FILE = "dev.sood.hermes.SEND_FILE";
|
||||
public static final String EXTRAS_FILE_URI = "file_url";
|
||||
public static final String EXTRAS_GROUP_OWNER_ADDRESS = "go_host";
|
||||
public static final String EXTRAS_GROUP_OWNER_PORT = "go_port";
|
||||
|
||||
public FileTransferService(String name) {
|
||||
super(name);
|
||||
Log.d(LocalFileTransferActivity.TAG, "In FileTransferService constructor");
|
||||
}
|
||||
|
||||
public FileTransferService() {
|
||||
super("FileTransferService");
|
||||
Log.d(LocalFileTransferActivity.TAG, "In FileTransferService constructor");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see android.app.IntentService#onHandleIntent(android.content.Intent)
|
||||
*/
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
|
||||
Log.d(LocalFileTransferActivity.TAG, "In onHandleIntent");
|
||||
|
||||
Context context = getApplicationContext();
|
||||
if (intent.getAction().equals(ACTION_SEND_FILE)) {
|
||||
|
||||
Log.d(LocalFileTransferActivity.TAG, "In main if-else");
|
||||
|
||||
String fileUriString = intent.getExtras().getString(EXTRAS_FILE_URI);
|
||||
String host = intent.getExtras().getString(EXTRAS_GROUP_OWNER_ADDRESS);
|
||||
Socket socket = new Socket();
|
||||
int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);
|
||||
|
||||
try {
|
||||
Log.d(LocalFileTransferActivity.TAG, "Opening client socket - ");
|
||||
socket.bind(null);
|
||||
socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);
|
||||
|
||||
Log.d(LocalFileTransferActivity.TAG, "Client socket - " + socket.isConnected());
|
||||
OutputStream stream = socket.getOutputStream();
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = cr.openInputStream(Uri.parse(fileUriString));
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.d(LocalFileTransferActivity.TAG, e.toString());
|
||||
}
|
||||
DeviceListFragment.copyFile(is, stream);
|
||||
Log.d(LocalFileTransferActivity.TAG, "Client: Data written");
|
||||
} catch (IOException e) {
|
||||
Log.e(LocalFileTransferActivity.TAG, e.getMessage());
|
||||
} finally {
|
||||
if (socket != null) {
|
||||
if (socket.isConnected()) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
// Give up
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +1,70 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager.local_file_transfer;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Dialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.LocationManager;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.WpsInfo;
|
||||
import android.net.wifi.p2p.WifiP2pConfig;
|
||||
import android.net.wifi.p2p.WifiP2pDevice;
|
||||
import android.net.wifi.p2p.WifiP2pManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
import android.os.Environment;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import org.kiwix.kiwixmobile.R;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class LocalFileTransferActivity extends AppCompatActivity {
|
||||
public class LocalFileTransferActivity extends AppCompatActivity implements WifiP2pManager.ChannelListener, DeviceListFragment.DeviceActionListener {
|
||||
|
||||
/*TODO
|
||||
* - Fix activity closure upon file transfer (successful or otherwise)
|
||||
* - Handle multiple selected files
|
||||
* */
|
||||
|
||||
public static final String TAG = "LocalFileTransferActvty";
|
||||
public static Uri filePath = null; // = Environment.getExternalStorageDirectory() + "/Kiwix/temp.txt";///psiram_en_all_2018-09.zim";//Notes/Granblue Fantasy Wiki/Main Page.txt";
|
||||
private final int PERMISSION_REQUEST_CODE_COARSE_LOCATION = 1;
|
||||
|
||||
private boolean isWifiP2pEnabled = false;
|
||||
private boolean retryChannel = false;
|
||||
|
||||
private WifiP2pManager manager;
|
||||
private final IntentFilter intentFilter = new IntentFilter();
|
||||
private WifiP2pManager.Channel channel;
|
||||
private BroadcastReceiver receiver = null;
|
||||
private Boolean fileSendingDevice = false; // True if intent has file uri
|
||||
// TODO: Set to true if activity opening intent has the file URI
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_local_file_transfer);
|
||||
|
||||
/*setContentView(R.layout.activity_local_file_transfer);
|
||||
|
||||
TextView fileUriListView = findViewById(R.id.text_view_file_uris);
|
||||
|
||||
Intent filesIntent = getIntent();
|
||||
@ -30,7 +77,509 @@ public class LocalFileTransferActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
fileUriListView.setText(uriList);
|
||||
fileUriListView.setText(uriList);*/
|
||||
|
||||
Intent filesIntent = getIntent();
|
||||
ArrayList<Uri> fileURIArrayList = filesIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
|
||||
|
||||
if(fileURIArrayList != null && fileURIArrayList.size() > 0) {
|
||||
filePath = fileURIArrayList.get(0);
|
||||
setFileSender();
|
||||
}
|
||||
|
||||
Toolbar actionBar = findViewById(R.id.toolbar_local_file_transfer);
|
||||
setSupportActionBar(actionBar);
|
||||
|
||||
// Intents that the broadcast receiver will be responding to
|
||||
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
|
||||
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
|
||||
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
|
||||
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
|
||||
|
||||
//TODO: Start WiFi
|
||||
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
|
||||
channel = manager.initialize(this, getMainLooper(), null);
|
||||
|
||||
// TODO: Add manager.removeGroup(channel, null); to remove previous groups
|
||||
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
&& checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
if(shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_COARSE_LOCATION)) {
|
||||
showNeutralDialog("Location permission is required to locate peer devices\n\nUser location is not being tracked by the app");
|
||||
//TODO: Close activity
|
||||
}
|
||||
|
||||
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_CODE_COARSE_LOCATION);
|
||||
}
|
||||
|
||||
requestExternalStorageWritePermission();
|
||||
}
|
||||
|
||||
private boolean requestExternalStorageWritePermission() {
|
||||
if(Build.VERSION.SDK_INT >= 23) { // For Marshmallow & higher API levels
|
||||
|
||||
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
if(shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
/* shouldShowRequestPermissionRationale() returns false when:
|
||||
* 1) User has previously checked on "Don't ask me again", and/or
|
||||
* 2) Permission has been disabled on device
|
||||
*/
|
||||
Toast.makeText(getApplicationContext(), "Required for file access", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
|
||||
}
|
||||
|
||||
} else { // For Android versions below Marshmallow 6.0 (API 23)
|
||||
return true; // As already requested at install time
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isWifiP2pEnabled() {
|
||||
return isWifiP2pEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.wifi_file_share_items, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if(item.getItemId() == R.id.menu_item_search_devices) {
|
||||
// Initiate discovery
|
||||
//TODO
|
||||
if(!isWifiP2pEnabled) {
|
||||
requestEnableWifiP2pServices();
|
||||
return true;
|
||||
}
|
||||
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !isLocationServicesEnabled()) {
|
||||
requestEnableLocationServices();
|
||||
return true;
|
||||
}
|
||||
|
||||
final DeviceListFragment deviceListFragment = (DeviceListFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_device_list);
|
||||
deviceListFragment.onInitiateDiscovery();
|
||||
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
Toast.makeText(LocalFileTransferActivity.this, "Discovery Initiated", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int reason) {
|
||||
Toast.makeText(LocalFileTransferActivity.this, "Discovery Failed: " + getErrorMessage(reason), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
} else if(item.getItemId() == R.id.menu_item_disconnect) {
|
||||
if(manager != null) {
|
||||
// TODO: 'cancelDisconnect', for removing the indefinite progress bar
|
||||
//removeGroupDetails();
|
||||
disconnect();
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeGroupDetails() {
|
||||
try {
|
||||
Method deletePersistentGroup = manager.getClass().getMethod("deletePersistentGroup", WifiP2pManager.Channel.class, int.class, WifiP2pManager.ActionListener.class);
|
||||
for(int netId = 0; netId < 32; netId++) {
|
||||
deletePersistentGroup.invoke(manager, channel, netId, new WifiP2pManager.ActionListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
Log.d(TAG, "WiFi Direct Group successfully deleted");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int reason) {
|
||||
Log.d(TAG, "Group deletion failed: "+getErrorMessage(reason));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.d(TAG, "Error removing group details: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLocationServicesEnabled() {
|
||||
LocationManager locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
|
||||
boolean gps_enabled = false;
|
||||
boolean network_enabled = false;
|
||||
|
||||
try {
|
||||
gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
|
||||
} catch(Exception ex) {ex.printStackTrace();}
|
||||
|
||||
try {
|
||||
network_enabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
|
||||
} catch(Exception ex) {ex.printStackTrace();}
|
||||
|
||||
/*if(!gps_enabled && !network_enabled) {
|
||||
// notify user
|
||||
|
||||
}*/
|
||||
|
||||
return (gps_enabled || network_enabled);
|
||||
}
|
||||
|
||||
private void requestEnableLocationServices() {
|
||||
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
Fragment prev = getSupportFragmentManager().findFragmentByTag("LocationDialog");
|
||||
if(prev != null) {
|
||||
fragmentTransaction.remove(prev); // To prevent multiple instances of the DialogFragment
|
||||
}
|
||||
fragmentTransaction.addToBackStack(null);
|
||||
|
||||
RequestEnableLocationServicesDialog dialogFragment = new RequestEnableLocationServicesDialog();
|
||||
// For DialogFragments, show() handles the fragment commit and display
|
||||
dialogFragment.show(fragmentTransaction, "LocationDialog");
|
||||
|
||||
}
|
||||
|
||||
public static class RequestEnableLocationServicesDialog extends DialogFragment {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setMessage("Enable location to allow detection of peers")
|
||||
.setPositiveButton("Open Location Settings", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
|
||||
paramDialogInterface.cancel();
|
||||
startActivityForResult(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), 1);
|
||||
}
|
||||
})
|
||||
.setNegativeButton("No", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
//TODO: Close activity
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
|
||||
private void requestEnableWifiP2pServices() {
|
||||
|
||||
/*new AlertDialog.Builder(this)
|
||||
.setMessage("Enable WiFi P2P from system settings")
|
||||
.setPositiveButton("Open WiFi Settings", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
|
||||
paramDialogInterface.cancel();
|
||||
startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
|
||||
}
|
||||
})
|
||||
.setNegativeButton("No", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
|
||||
}
|
||||
})
|
||||
.show();*/
|
||||
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
Fragment prev = getSupportFragmentManager().findFragmentByTag("WifiP2pDialog");
|
||||
if(prev != null) {
|
||||
fragmentTransaction.remove(prev); // To prevent multiple instances of the DialogFragment
|
||||
}
|
||||
fragmentTransaction.addToBackStack(null);
|
||||
|
||||
RequestEnableWifiP2pServicesDialog dialogFragment = new RequestEnableWifiP2pServicesDialog();
|
||||
// For DialogFragments, show() handles the fragment commit and display
|
||||
dialogFragment.show(fragmentTransaction, "WifiP2pDialog");
|
||||
}
|
||||
|
||||
public static class RequestEnableWifiP2pServicesDialog extends DialogFragment {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setMessage("Enable WiFi P2P from system settings")
|
||||
.setPositiveButton("Open WiFi Settings", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
|
||||
paramDialogInterface.cancel();
|
||||
startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
|
||||
}
|
||||
})
|
||||
.setNegativeButton("No", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
//TODO: Close activity
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
switch (requestCode) {
|
||||
case 1: {
|
||||
LocationManager locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
|
||||
|
||||
if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
|
||||
return;
|
||||
} else {
|
||||
/*new AlertDialog.Builder(this)
|
||||
.setMessage("Cannot discover peers without location services")
|
||||
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
//((MainActivity) getApplicationContext()).finish();
|
||||
}
|
||||
})
|
||||
.show();*/
|
||||
showNeutralDialog("Cannot discover peers without location services");
|
||||
//TODO: Close activity
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getErrorMessage(int reason) {
|
||||
String error = "";
|
||||
switch (reason) {
|
||||
case WifiP2pManager.ERROR: error = "Internal error"; break;
|
||||
case WifiP2pManager.BUSY: error = "Framework busy, unable to service request"; break;
|
||||
case WifiP2pManager.P2P_UNSUPPORTED: error = "P2P unsupported on this device"; break;
|
||||
|
||||
default: error = "Unknown error code - "+reason; break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
/*if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !isLocationServicesEnabled()) {
|
||||
requestEnableLocationServices();
|
||||
}*/
|
||||
//TODO
|
||||
receiver = new WifiDirectBroadcastReceiver(manager, channel, this);
|
||||
registerReceiver(receiver, intentFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
//TODO
|
||||
unregisterReceiver(receiver);
|
||||
}
|
||||
|
||||
public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled) {
|
||||
this.isWifiP2pEnabled = isWifiP2pEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case PERMISSION_REQUEST_CODE_COARSE_LOCATION : {
|
||||
if(grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.e(TAG, "Location permission not granted");
|
||||
|
||||
showNeutralDialog("Cannot locate peer devices without location permissions");
|
||||
//TODO: Close activity
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case 0: break;
|
||||
}
|
||||
}
|
||||
|
||||
public void resetPeers() {
|
||||
DeviceListFragment deviceListFragment = (DeviceListFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_device_list);
|
||||
if(deviceListFragment != null) {
|
||||
deviceListFragment.clearPeers();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelDisconnected() {
|
||||
//TODO
|
||||
if(manager != null && !retryChannel) {
|
||||
Toast.makeText(this, "Channel lost, trying again", Toast.LENGTH_LONG).show();
|
||||
resetData();
|
||||
retryChannel = true;
|
||||
manager.initialize(this, getMainLooper(), this);
|
||||
|
||||
} else {
|
||||
Toast.makeText(this, "Severe! Try Disable/Re-enable WiFi P2P", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
public void resetData() {
|
||||
DeviceListFragment deviceListFragment = (DeviceListFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_device_list);
|
||||
if(deviceListFragment != null) {
|
||||
deviceListFragment.clearPeers();
|
||||
}
|
||||
}
|
||||
|
||||
private void showNeutralDialog(String dialogMessage) {
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
Fragment prev = getSupportFragmentManager().findFragmentByTag("NeutralDialog");
|
||||
if(prev != null) {
|
||||
fragmentTransaction.remove(prev); // To prevent multiple instances of the DialogFragment
|
||||
}
|
||||
fragmentTransaction.addToBackStack(null);
|
||||
|
||||
NeutralDialog dialogFragment = new NeutralDialog(dialogMessage);
|
||||
// For DialogFragments, show() handles the fragment commit and display
|
||||
dialogFragment.show(fragmentTransaction, "NeutralDialog");
|
||||
}
|
||||
|
||||
public static class NeutralDialog extends DialogFragment {
|
||||
|
||||
private String dialogMessage = "";
|
||||
|
||||
public NeutralDialog() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NeutralDialog(String message) {
|
||||
super();
|
||||
this.dialogMessage = message;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setMessage(dialogMessage)
|
||||
.setNeutralButton("Dismiss", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeDeviceName(String deviceNewName) {
|
||||
try {
|
||||
Method method = manager.getClass().getMethod("setDeviceName", WifiP2pManager.Channel.class, String.class, WifiP2pManager.ActionListener.class);
|
||||
method.invoke(manager, channel, deviceNewName, new WifiP2pManager.ActionListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
Toast.makeText(LocalFileTransferActivity.this, "Name successfully changed", Toast.LENGTH_LONG).show();
|
||||
resetPeers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int reason) {
|
||||
Toast.makeText(LocalFileTransferActivity.this, "Request failed: " + reason, Toast.LENGTH_SHORT).show();
|
||||
Log.d(TAG, "Name change failed: " + getErrorMessage(reason));
|
||||
}
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFileSender() {
|
||||
return fileSendingDevice;
|
||||
}
|
||||
|
||||
public void setFileSender() {
|
||||
fileSendingDevice = true;
|
||||
}
|
||||
|
||||
/*@Override
|
||||
public void showDetails(WifiP2pDevice device) {
|
||||
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public void cancelDisconnect() {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(final WifiP2pDevice peerDevice) {
|
||||
WifiP2pConfig config = new WifiP2pConfig();
|
||||
config.deviceAddress = peerDevice.deviceAddress;
|
||||
config.wps.setup = WpsInfo.PBC;
|
||||
|
||||
// If self sender, then receiver will be group owner
|
||||
if(isFileSender())
|
||||
config.groupOwnerIntent = 0; // Sets inclination for own device. This way other device has got to be the owner.
|
||||
// Maybe reset the previous wifi direct group data, which is causing a fixed group owner
|
||||
|
||||
/*else
|
||||
config.groupOwnerIntent = 15;*/
|
||||
|
||||
//TODO: Show a progress bar between starting & completion of connection
|
||||
|
||||
manager.connect(channel, config, new WifiP2pManager.ActionListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
//Toast.makeText(MainActivity.this, "Connected to " + peerDevice.deviceName, Toast.LENGTH_SHORT).show();
|
||||
// UI updated from broadcast receiver
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int reason) {
|
||||
Toast.makeText(LocalFileTransferActivity.this, "Connection failed: " + getErrorMessage(reason), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
fileSendingDevice = false;
|
||||
|
||||
//TODO
|
||||
manager.removeGroup(channel, new WifiP2pManager.ActionListener() {
|
||||
|
||||
@Override
|
||||
public void onFailure(int reasonCode) {
|
||||
Log.d(TAG, "Disconnect failed. Reason :" + reasonCode);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
Log.d(TAG, "Disconnect successful");
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,75 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager.local_file_transfer;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.p2p.WifiP2pDevice;
|
||||
import android.net.wifi.p2p.WifiP2pManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.kiwix.kiwixmobile.R;
|
||||
|
||||
public class WifiDirectBroadcastReceiver extends BroadcastReceiver {
|
||||
|
||||
private WifiP2pManager manager;
|
||||
private WifiP2pManager.Channel channel;
|
||||
private LocalFileTransferActivity wifiActivity;
|
||||
|
||||
public WifiDirectBroadcastReceiver(WifiP2pManager manager, WifiP2pManager.Channel channel, LocalFileTransferActivity activity) {
|
||||
super();
|
||||
this.manager = manager;
|
||||
this.channel = channel;
|
||||
this.wifiActivity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
|
||||
if(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
|
||||
|
||||
int wifiP2pState = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
|
||||
if(wifiP2pState == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
|
||||
wifiActivity.setIsWifiP2pEnabled(true);
|
||||
} else {
|
||||
wifiActivity.setIsWifiP2pEnabled(false);
|
||||
Toast.makeText(wifiActivity, "Cannot discover peers without WiFi", Toast.LENGTH_SHORT).show();
|
||||
//TODO
|
||||
wifiActivity.resetPeers();
|
||||
}
|
||||
Log.d(wifiActivity.TAG, "WiFi P2P state changed - " + wifiP2pState);
|
||||
|
||||
} else if(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
|
||||
|
||||
if(manager != null) {
|
||||
//TODO
|
||||
manager.requestPeers(channel, (WifiP2pManager.PeerListListener) wifiActivity.getSupportFragmentManager().findFragmentById(R.id.fragment_device_list));
|
||||
}
|
||||
Log.d(wifiActivity.TAG, "P2P peers changed");
|
||||
|
||||
} else if(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
|
||||
|
||||
if(manager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
|
||||
|
||||
if(networkInfo.isConnected()) {
|
||||
//TODO
|
||||
//
|
||||
|
||||
manager.requestConnectionInfo(channel, (DeviceListFragment) wifiActivity.getSupportFragmentManager().findFragmentById(R.id.fragment_device_list));
|
||||
} else {
|
||||
wifiActivity.resetData();
|
||||
}
|
||||
|
||||
} else if(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
|
||||
//TODO
|
||||
DeviceListFragment deviceListFragment = (DeviceListFragment) wifiActivity.getSupportFragmentManager().findFragmentById(R.id.fragment_device_list);
|
||||
deviceListFragment.updateUserDevice((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
|
||||
}
|
||||
}
|
||||
}
|
9
app/src/main/res/drawable/ic_baseline_cancel_24px.xml
Normal file
9
app/src/main/res/drawable/ic_baseline_cancel_24px.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z"/>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_baseline_edit_24px.xml
Normal file
9
app/src/main/res/drawable/ic_baseline_edit_24px.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M17,1.01L7,1c-1.1,0 -1.99,0.9 -1.99,2v18c0,1.1 0.89,2 1.99,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14zM12.8,13.22v1.75l3.2,-2.99L12.8,9v1.7c-3.11,0.43 -4.35,2.56 -4.8,4.7 1.11,-1.5 2.58,-2.18 4.8,-2.18z"/>
|
||||
</vector>
|
@ -1,3 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".zim_manager.local_file_transfer.LocalFileTransferActivity">>
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/app_bar_local_file_transfer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/container_local_file_transfer">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar_local_file_transfer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/container_local_file_transfer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/app_bar_local_file_transfer"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<fragment
|
||||
class="org.kiwix.kiwixmobile.zim_manager.local_file_transfer.DeviceListFragment"
|
||||
android:id="@+id/fragment_device_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="2"/>
|
||||
|
||||
<!--<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:background="@android:color/darker_gray"/>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/fragment_device_detail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="5"/>-->
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<!--
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
@ -18,3 +79,4 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
-->
|
||||
|
22
app/src/main/res/layout/dialog_edit_device_name.xml
Normal file
22
app/src/main/res/layout/dialog_edit_device_name.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp">
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Change Device Name"
|
||||
android:textStyle="bold"
|
||||
android:textSize="17sp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/edit_text_change_device_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Enter name"
|
||||
android:textSize="15sp"/>
|
||||
|
||||
</LinearLayout>
|
136
app/src/main/res/layout/fragment_device_list.xml
Normal file
136
app/src/main/res/layout/fragment_device_list.xml
Normal file
@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view_your_device"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingRight="5dp"
|
||||
android:paddingBottom="1dp"
|
||||
android:text="Your Device:"
|
||||
android:textSize="13sp"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@id/btn_edit_device_name"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view_device_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintTop_toBottomOf="@+id/text_view_your_device"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@id/btn_edit_device_name"
|
||||
android:text="Device Name"
|
||||
android:textStyle="bold"
|
||||
android:textSize="17sp"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view_device_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintTop_toBottomOf="@+id/text_view_device_name"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@id/btn_edit_device_name"
|
||||
android:text="Status"
|
||||
android:textSize="15sp"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"
|
||||
android:paddingBottom="5dp"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/view_device_list_boundary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:background="#0000f0"
|
||||
app:layout_constraintTop_toBottomOf="@+id/text_view_device_status"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_edit_device_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_baseline_edit_24px"
|
||||
android:tooltipText="Edit Name"
|
||||
android:background="@android:color/transparent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/view_device_list_boundary"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingStart="15dp"
|
||||
android:paddingRight="5dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginEnd="20dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view_available_device"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="NEARBY DEVICES"
|
||||
android:gravity="center"
|
||||
android:textSize="16sp"
|
||||
android:fontFamily="monospace"
|
||||
app:layout_constraintTop_toBottomOf="@+id/view_device_list_boundary"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:paddingTop="5dp"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/frame_layout_peer_devices"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@+id/text_view_available_device"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:visibility="invisible">
|
||||
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</ListView>
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/empty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="No devices detected\nTap on search button to try again"
|
||||
android:gravity="center"
|
||||
android:layout_margin="50dp"
|
||||
android:textColor="@android:color/black" />
|
||||
<!--android:visibility="gone"-->
|
||||
</FrameLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar_searching_peers"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true"
|
||||
android:layout_margin="50dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/text_view_available_device"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:visibility="gone"/>
|
||||
|
||||
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
34
app/src/main/res/layout/row_peer_device.xml
Normal file
34
app/src/main/res/layout/row_peer_device.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal" android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/row_device_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="3"
|
||||
android:gravity="center_vertical"
|
||||
android:text="Device Name"
|
||||
android:tooltipText="Device Name"
|
||||
android:textStyle="bold"
|
||||
android:textSize="17sp"
|
||||
android:paddingTop="1dp"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/row_device_status"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="2"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="Status"
|
||||
android:tooltipText="Device Status"
|
||||
android:textSize="17sp"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"
|
||||
android:paddingBottom="1dp"/>
|
||||
|
||||
</LinearLayout>
|
@ -10,6 +10,13 @@
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
app:iconifiedByDefault="true"
|
||||
app:showAsAction="always|collapseActionView"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/get_zim_nearby_device"
|
||||
android:icon="@drawable/ic_baseline_mobile_screen_share_24px"
|
||||
android:title="Get content from nearby device"
|
||||
app:showAsAction="always"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/select_language"
|
||||
android:icon="@drawable/ic_language_white_24dp"
|
||||
|
16
app/src/main/res/menu/wifi_file_share_items.xml
Normal file
16
app/src/main/res/menu/wifi_file_share_items.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".zim_manager.local_file_transfer.LocalFileTransferActivity">
|
||||
|
||||
<item android:id="@+id/menu_item_disconnect"
|
||||
android:title="Disconnect"
|
||||
app:showAsAction="always"
|
||||
android:icon="@drawable/ic_baseline_cancel_24px" />
|
||||
|
||||
<item android:id="@+id/menu_item_search_devices"
|
||||
android:title="Search For Peers"
|
||||
app:showAsAction="always"
|
||||
android:icon="@drawable/action_search"/>
|
||||
</menu>
|
Loading…
x
Reference in New Issue
Block a user