I'm trying to implement file transfer using Nearby Connection with P2P_STAR strategy where the "spoke" sends a video file to the "hub".
Using the documentation example I send the filenameMessage as bytes payload and the file payload. The receiver uses the SimpleArrayMaps to store the filename, incoming and completed payloads to rename the file later on. Target is Q with android:requestLegacyExternalStorage="true"
, because Uri uri = filePayload.asFile().asUri();
is using a method not yet implemented I think.
Sending messages works fine but when it comes to file transfer only a part of it is transfered. For example I had a video around 24MB and the transfered file in the download/nearby folder was 17MB, and I waited many minutes. Other times the transferred file was a few KB.
My code, one activity app(device is either spoke or hub):
public void sendMessage(String endpointId, String msg) {
if (endpointId != null) {
// Convert the message to Bytes
byte[] bytes = msg.getBytes(StandardCharsets.UTF_8);
// Generate payload and send it to destination
Payload bytesPayload = Payload.fromBytes(bytes);
Nearby.getConnectionsClient(context).sendPayload(endpointId, bytesPayload);
}
}
private PayloadCallback payloadCallback = new PayloadCallback() {
private SimpleArrayMap<Long, Payload> incomingFilePayloads = new SimpleArrayMap<>();
private SimpleArrayMap<Long, Payload> completedFilePayloads = new SimpleArrayMap<>();
private SimpleArrayMap<Long, String> filePayloadFilenames = new SimpleArrayMap<>();
@Override
public void onPayloadReceived(@NonNull String endpointId, @NonNull Payload payload) {
if (payload.getType() == Payload.Type.BYTES) {
// Convert the payload from Bytes to a String
String msg = new String(payload.asBytes(), StandardCharsets.UTF_8);
// Check if it's the filename bytes payload
String[] parts = msg.split(":");
if (parts[0].equals("filename")) {
msg = parts[0];
}
switch (msg) {
// OTHER CASES...
case "create_video":
//Video created here
sendRecording(endpointId);
break;
case "filename":
long payloadId = Long.parseLong(parts[1]);
String filename = "video_" + parts[2] + ".mp4";
filePayloadFilenames.put(payloadId, filename);
processFilePayload(payload.getId());
break;
}
} else {
if (payload.getType() == Payload.Type.FILE)
incomingFilePayloads.put(payload.getId(), payload);
}
}
@Override
public void onPayloadTransferUpdate(@NonNull String endpointId, @NonNull PayloadTransferUpdate payloadTransferUpdate) {
if (payloadTransferUpdate.getStatus() == PayloadTransferUpdate.Status.SUCCESS) {
long payloadId = payloadTransferUpdate.getPayloadId();
Payload payload = incomingFilePayloads.remove(payloadId);
// ALWAYS NULL?
if (payload != null) {
completedFilePayloads.put(payloadId, payload);
if (payload.getType() == Payload.Type.FILE) {
processFilePayload(payloadId);
}
}
}
}
private void processFilePayload(long payloadId) {
Payload filePayload = completedFilePayloads.get(payloadId);
String filename = filePayloadFilenames.get(payloadId);
if (filePayload != null && filename != null) {
completedFilePayloads.remove(payloadId);
filePayloadFilenames.remove(payloadId);
File payloadFile = filePayload.asFile().asJavaFile();
payloadFile.renameTo(new File(payloadFile.getParentFile(), filename));
}
}
};
private void sendRecording(String endpointId) {
// The uri is saved when I create the file in the first place
Uri uri = Utils.getUriSavedVideo();
Payload videoPayload = null;
try {
ParcelFileDescriptor video = getContentResolver().openFileDescriptor(uri, "r");
videoPayload = Payload.fromFile(video);
String filenameMsg = "filename" + ":" + videoPayload.getId() + ":" + Utils.getTimeStampString();
sendMessage(endpointId, filenameMsg);
Nearby.getConnectionsClient(context).sendPayload(endpointId, videoPayload);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
I've noticed that inside method onPayloadTransferUpdate the payload is always null when retrived from incomingFilePayload, but the payloadId get inserted in incomingFilePayload inside onPayloadReceived Payload.Type.FILE. However this part should only be relevant to renaming the file, manually renaming the file doesn't work because the video file is incomplete.
Since at least a part of the file is transferred could this be related to the devices themselves? The connection is still in place and I can still send other messages. I thought that the STAR strategy was fine to send small videos in a short period of time.