feat: update file transfer api
Change-Id: I278cea3dad005d41457df4aab75ff1cc46b517e1
diff --git a/ring-android/.gitignore b/ring-android/.gitignore
index 828d430..0c457c6 100644
--- a/ring-android/.gitignore
+++ b/ring-android/.gitignore
@@ -41,15 +41,7 @@
/app/build/
/androidtv/build/
/libringclient/build/
-/libringclient/src/main/java/cx/ring/daemon/Blob.java
-/libringclient/src/main/java/cx/ring/daemon/FloatVect.java
-/libringclient/src/main/java/cx/ring/daemon/Ringservice.java
-/libringclient/src/main/java/cx/ring/daemon/RingserviceJNI.java
-/libringclient/src/main/java/cx/ring/daemon/UintVect.java
-/libringclient/src/main/java/cx/ring/daemon/VideoCallback.java
-/libringclient/src/main/java/cx/ring/daemon/PresenceCallback.java
-/libringclient/src/main/java/cx/ring/daemon/DataTransferCallback.java
-/libringclient/src/main/java/cx/ring/daemon/DataTransferInfo.java
+/libringclient/src/main/java/cx/ring/daemon/*
/build/
/app/google-services.json
/app/src/debug/google-services.json
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java
index 460b138..764bcc9 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java
@@ -39,6 +39,8 @@
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.Toast;
@@ -100,6 +102,12 @@
@BindView(R.id.number_selector)
protected Spinner mNumberSpinner;
+ @BindView(R.id.pb_data_transfer)
+ protected ProgressBar pbDataTransfer;
+
+ @BindView(R.id.send_data)
+ protected ImageButton sendData;
+
private AlertDialog mDeleteDialog;
private boolean mDeleteConversation = false;
@@ -193,7 +201,7 @@
presenter.sendTextMessage(mMsgEditTxt.getText().toString());
}
- @OnClick(R.id.file_send)
+ @OnClick(R.id.send_data)
public void selectFile() {
presenter.selectFile();
}
@@ -215,6 +223,34 @@
}
@Override
+ public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
+ super.onActivityResult(requestCode, resultCode, resultData);
+
+ if (requestCode == REQUEST_CODE_FILE_PICKER && resultCode == RESULT_OK) {
+ if (resultData != null) {
+ android.net.Uri uri = resultData.getData();
+ if (uri == null) {
+ return;
+ }
+
+ new Thread(() -> {
+ getActivity().runOnUiThread(() -> setLoading(true));
+
+ try {
+ File cacheFile = FileUtils.getCacheFile(getActivity(), uri);
+ presenter.sendFile(cacheFile.toString());
+ } catch (IOException e) {
+ Log.e(TAG, "onActivityResult: not able to create cache file");
+ getActivity().runOnUiThread(() -> displayErrorToast(RingError.INVALID_FILE));
+ }
+
+ getActivity().runOnUiThread(() -> setLoading(false));
+ }).start();
+ }
+ }
+ }
+
+ @Override
public void writeCacheFile(String cacheFilename) {
File cacheFile = new File(getActivity().getCacheDir(), cacheFilename);
try {
@@ -230,28 +266,6 @@
}
}
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
- super.onActivityResult(requestCode, resultCode, resultData);
-
- if (requestCode == REQUEST_CODE_FILE_PICKER && resultCode == RESULT_OK) {
- if (resultData != null) {
- android.net.Uri uri = resultData.getData();
- if (uri == null) {
- return;
- }
-
- try {
- File cacheFile = FileUtils.getCacheFile(getActivity(), uri);
- presenter.sendFile(cacheFile.toString());
- } catch (IOException e) {
- Log.e(TAG, "onActivityResult: not able to create cache file");
- displayErrorToast(RingError.INVALID_FILE);
- }
- }
- }
- }
-
@OnEditorAction(R.id.msg_input_txt)
public boolean actionSendMsgText(int actionId) {
switch (actionId) {
@@ -500,4 +514,14 @@
public void toggleButtonClicked() {
presenter.clickOnGoingPane();
}
+
+ private void setLoading(boolean isLoading) {
+ if (isLoading) {
+ sendData.setVisibility(View.GONE);
+ pbDataTransfer.setVisibility(View.VISIBLE);
+ } else {
+ sendData.setVisibility(View.VISIBLE);
+ pbDataTransfer.setVisibility(View.GONE);
+ }
+ }
}
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.java b/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.java
index 5eb4edc..8b988ee 100644
--- a/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.java
+++ b/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.java
@@ -501,22 +501,23 @@
case DATA_TRANSFER: {
Long transferId = event.getEventInput(ServiceEvent.EventInput.TRANSFER_ID, Long.class);
DataTransferEventCode transferEventCode = event.getEventInput(ServiceEvent.EventInput.TRANSFER_EVENT_CODE, DataTransferEventCode.class);
- DataTransferInfo dataTransferInfo = mCallService.dataTransferInfo(transferId);
+ DataTransferInfo dataTransferInfo = new DataTransferInfo();
+ mCallService.dataTransferInfo(transferId, dataTransferInfo);
if (transferEventCode == DataTransferEventCode.CREATED) {
HistoryFileTransfer historyFileTransfer = new HistoryFileTransfer(transferId, dataTransferInfo.getDisplayName(),
- dataTransferInfo.getIsOutgoing(), dataTransferInfo.getTotalSize(),
+ dataTransferInfo.getFlags() == 0, dataTransferInfo.getTotalSize(),
dataTransferInfo.getBytesProgress(), dataTransferInfo.getPeer(),
dataTransferInfo.getAccountId());
mHistoryService.addFileTransfer(historyFileTransfer);
- if (!dataTransferInfo.getIsOutgoing()) {
+ if (dataTransferInfo.getFlags() == 1){
showFileTransferNotification(transferId, dataTransferInfo.getPeer());
}
}
- if (!dataTransferInfo.getIsOutgoing()) {
+ if (dataTransferInfo.getFlags() == 1) {
mHistoryService.updateFileTransferStatus(transferId, transferEventCode);
}
diff --git a/ring-android/app/src/main/res/layout/frag_conversation.xml b/ring-android/app/src/main/res/layout/frag_conversation.xml
index 5a2bbbc..bf07c4a 100644
--- a/ring-android/app/src/main/res/layout/frag_conversation.xml
+++ b/ring-android/app/src/main/res/layout/frag_conversation.xml
@@ -51,6 +51,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:gravity="center"
android:orientation="horizontal">
<Spinner
@@ -73,16 +74,23 @@
android:padding="8dp" />
<ImageButton
- android:id="@+id/file_send"
+ android:id="@+id/send_data"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:layout_marginEnd="5dp"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/send_file"
- android:layout_marginEnd="5dp"
android:padding="8dp"
android:tint="@android:color/darker_gray"
card_view:srcCompat="@drawable/ic_upload_black" />
+ <ProgressBar
+ android:id="@+id/pb_data_transfer"
+ android:layout_width="30dp"
+ android:layout_height="30dp"
+ android:indeterminate="true"
+ android:visibility="gone" />
+
<ImageButton
android:id="@+id/msg_send"
android:layout_width="wrap_content"
diff --git a/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java b/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java
index 643e4d5..605dfe1 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java
@@ -30,6 +30,7 @@
import cx.ring.model.CallContact;
import cx.ring.model.Conference;
import cx.ring.model.Conversation;
+import cx.ring.model.DataTransferError;
import cx.ring.model.DataTransferEventCode;
import cx.ring.model.HistoryCall;
import cx.ring.model.HistoryFileTransfer;
@@ -43,6 +44,7 @@
import cx.ring.services.AccountService;
import cx.ring.services.CallService;
import cx.ring.services.ContactService;
+import cx.ring.services.DataTransferWrapper;
import cx.ring.services.DeviceRuntimeService;
import cx.ring.services.HardwareService;
import cx.ring.services.HistoryService;
@@ -205,7 +207,12 @@
// send file
Uri uri = new Uri(mContactRingId);
- mCallService.sendFile(mAccountId, uri.getHost(), filePath, file.getName());
+ DataTransferInfo dataTransferInfo = new DataTransferInfo();
+ dataTransferInfo.setAccountId(mAccountId);
+ dataTransferInfo.setPeer(uri.getHost());
+ dataTransferInfo.setPath(filePath);
+ dataTransferInfo.setDisplayName(file.getName());
+ mCallService.sendFile(0L, dataTransferInfo);
}
public void sendTrustRequest() {
@@ -375,31 +382,30 @@
// find corresponding transfer
mConversation.updateFileTransfer(transferId, transferEventCode);
- DataTransferInfo dataTransferInfo = null;
+ DataTransferInfo dataTransferInfo = new DataTransferInfo();
+ DataTransferWrapper dataTransferWrapper = null;
if (transferEventCode == DataTransferEventCode.CREATED || transferEventCode == DataTransferEventCode.FINISHED) {
- dataTransferInfo = mCallService.dataTransferInfo(transferId);
+ dataTransferWrapper = mCallService.dataTransferInfo(transferId, dataTransferInfo);
+
+ if (dataTransferWrapper.getDataTransferError() != DataTransferError.SUCCESS) {
+ Log.e(TAG, "handleDataTransferEvent: an error occurred during data transfer " + dataTransferWrapper.getDataTransferError().name());
+ return;
+ }
}
+ Log.d(TAG, "handleDataTransferEvent: " + transferEventCode.name());
switch (transferEventCode) {
case CREATED:
- Log.i(TAG, "handleDataTransferEvent: CREATED");
-
- if (dataTransferInfo != null) {
- mConversation.addFileTransfer(transferId, dataTransferInfo.getDisplayName(),
- dataTransferInfo.getIsOutgoing(), dataTransferInfo.getTotalSize(),
- dataTransferInfo.getBytesProgress(), dataTransferInfo.getPeer(),
- dataTransferInfo.getAccountId());
- }
+ mConversation.addFileTransfer(transferId, dataTransferInfo.getDisplayName(),
+ dataTransferWrapper.isOutgoing(), dataTransferInfo.getTotalSize(),
+ dataTransferInfo.getBytesProgress(), dataTransferInfo.getPeer(),
+ dataTransferInfo.getAccountId());
break;
case FINISHED:
- if (dataTransferInfo != null) {
- if (!dataTransferInfo.getIsOutgoing()) {
- getView().writeCacheFile(dataTransferInfo.getDisplayName());
- }
+ if (!dataTransferWrapper.isOutgoing()) {
+ getView().writeCacheFile(dataTransferInfo.getDisplayName());
}
break;
- default:
- Log.d(TAG, "handleDataTransferEvent: " + transferEventCode.name());
}
Log.d(TAG, "handleDataTransferEvent: AggregateHistorySize=" + mConversation.getAggregateHistory().size() + ", transferEventCode=" + transferEventCode);
diff --git a/ring-android/libringclient/src/main/java/cx/ring/model/DataTransferError.java b/ring-android/libringclient/src/main/java/cx/ring/model/DataTransferError.java
new file mode 100644
index 0000000..5ac37ed
--- /dev/null
+++ b/ring-android/libringclient/src/main/java/cx/ring/model/DataTransferError.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004-2018 Savoir-faire Linux Inc.
+ *
+ * Author: Pierre Duchemin <pierre.duchemin@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package cx.ring.model;
+
+public enum DataTransferError {
+ SUCCESS,
+ UNKNOWN,
+ IO,
+ INVALID_ARGUMENT
+}
\ No newline at end of file
diff --git a/ring-android/libringclient/src/main/java/cx/ring/model/DataTransferEventCode.java b/ring-android/libringclient/src/main/java/cx/ring/model/DataTransferEventCode.java
index b1d14ed..35eda56 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/model/DataTransferEventCode.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/model/DataTransferEventCode.java
@@ -21,12 +21,13 @@
package cx.ring.model;
public enum DataTransferEventCode {
- CREATED(false),
+ INVALID,
+ CREATED,
UNSUPPORTED(true),
- WAIT_PEER_ACCEPTANCE(false),
- WAIT_HOST_ACCEPTANCE(false),
- ONGOING(false),
- FINISHED(false),
+ WAIT_PEER_ACCEPTANCE,
+ WAIT_HOST_ACCEPTANCE,
+ ONGOING,
+ FINISHED,
CLOSED_BY_HOST(true),
CLOSED_BY_PEER(true),
INVALID_PATHNAME(true),
@@ -34,6 +35,10 @@
private boolean isError;
+ DataTransferEventCode() {
+ isError = false;
+ }
+
DataTransferEventCode(boolean isError) {
this.isError = isError;
}
diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/CallService.java b/ring-android/libringclient/src/main/java/cx/ring/services/CallService.java
index ba9f29d..1e4647d 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/services/CallService.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/services/CallService.java
@@ -33,6 +33,7 @@
import cx.ring.daemon.Ringservice;
import cx.ring.daemon.StringMap;
import cx.ring.model.CallContact;
+import cx.ring.model.DataTransferError;
import cx.ring.model.DataTransferEventCode;
import cx.ring.model.ServiceEvent;
import cx.ring.model.SipCall;
@@ -426,63 +427,65 @@
);
}
- public DataTransferInfo dataTransferInfo(final Long dataTransferId) {
- return FutureUtils.executeDaemonThreadCallable(
- mExecutor,
- mDeviceRuntimeService.provideDaemonThreadId(),
- true,
- new Callable<DataTransferInfo>() {
- @Override
- public DataTransferInfo call() throws Exception {
- Log.i(TAG, "dataTransferInfo() thread running... dataTransferId=" + dataTransferId);
- return Ringservice.dataTransferInfo(dataTransferId);
- }
- }
- );
- }
-
- public Long sendFile(final String accountId, final String to, final String filePath, final String displayName) {
- return FutureUtils.executeDaemonThreadCallable(
+ public DataTransferError sendFile(final Long dataTransferId, final DataTransferInfo dataTransferInfo) {
+ Long errorCode = FutureUtils.executeDaemonThreadCallable(
mExecutor,
mDeviceRuntimeService.provideDaemonThreadId(),
true,
new Callable<Long>() {
@Override
public Long call() throws Exception {
- Log.i(TAG, "sendFile() thread running... accountId=" + accountId + ", to=" + to + ", filePath=" + filePath);
- return Ringservice.sendFile(accountId, to, filePath, displayName);
+ Log.i(TAG, "sendFile() thread running... accountId=" + dataTransferInfo.getAccountId() + ", peer=" + dataTransferInfo.getPeer() + ", filePath=" + dataTransferInfo.getPath());
+ return Ringservice.sendFile(dataTransferInfo, dataTransferId);
}
}
);
+ return getDataTransferError(errorCode);
}
- public void acceptFileTransfer(final Long dataTransferId, final String filePath, final long offset) {
- FutureUtils.executeDaemonThreadCallable(
+ public DataTransferError acceptFileTransfer(final Long dataTransferId, final String filePath, final long offset) {
+ Long errorCode = FutureUtils.executeDaemonThreadCallable(
mExecutor,
mDeviceRuntimeService.provideDaemonThreadId(),
true,
- new Callable<Boolean>() {
+ new Callable<Long>() {
@Override
- public Boolean call() throws Exception {
+ public Long call() throws Exception {
Log.i(TAG, "acceptFileTransfer() thread running... dataTransferId=" + dataTransferId + ", filePath=" + filePath + ", offset=" + offset);
- Ringservice.acceptFileTransfer(dataTransferId, filePath, offset);
- return true;
+ return Ringservice.acceptFileTransfer(dataTransferId, filePath, offset);
}
}
);
+ return getDataTransferError(errorCode);
}
- public void cancelDataTransfer(final Long dataTransferId) {
- FutureUtils.executeDaemonThreadCallable(
+ public DataTransferError cancelDataTransfer(final Long dataTransferId) {
+ Long errorCode = FutureUtils.executeDaemonThreadCallable(
mExecutor,
mDeviceRuntimeService.provideDaemonThreadId(),
true,
- new Callable<Boolean>() {
+ new Callable<Long>() {
@Override
- public Boolean call() throws Exception {
+ public Long call() throws Exception {
Log.i(TAG, "cancelDataTransfer() thread running... dataTransferId=" + dataTransferId);
- Ringservice.cancelDataTransfer(dataTransferId);
- return true;
+ return Ringservice.cancelDataTransfer(dataTransferId);
+ }
+ }
+ );
+ return getDataTransferError(errorCode);
+ }
+
+ public DataTransferWrapper dataTransferInfo(final Long dataTransferId, final DataTransferInfo dataTransferInfo) {
+ return FutureUtils.executeDaemonThreadCallable(
+ mExecutor,
+ mDeviceRuntimeService.provideDaemonThreadId(),
+ true,
+ new Callable<DataTransferWrapper>() {
+ @Override
+ public DataTransferWrapper call() throws Exception {
+ Log.i(TAG, "dataTransferInfo() thread running... dataTransferId=" + dataTransferId);
+ long errorCode = Ringservice.dataTransferInfo(dataTransferId, dataTransferInfo);
+ return new DataTransferWrapper(dataTransferInfo, getDataTransferError(errorCode));
}
}
);
@@ -596,12 +599,7 @@
}
public void dataTransferEvent(long transferId, int eventCode) {
- DataTransferEventCode dataTransferEventCode = DataTransferEventCode.UNSUPPORTED;
- try {
- dataTransferEventCode = DataTransferEventCode.values()[eventCode];
- } catch (ArrayIndexOutOfBoundsException ignored) {
- Log.e(TAG, "dataTransferEvent: invalid data transfer status from daemon");
- }
+ DataTransferEventCode dataTransferEventCode = getDataTransferEventCode(eventCode);
setChanged();
ServiceEvent event = new ServiceEvent(ServiceEvent.EventType.DATA_TRANSFER);
@@ -609,4 +607,28 @@
event.addEventInput(ServiceEvent.EventInput.TRANSFER_EVENT_CODE, dataTransferEventCode);
notifyObservers(event);
}
+
+ private static DataTransferEventCode getDataTransferEventCode(int eventCode) {
+ DataTransferEventCode dataTransferEventCode = DataTransferEventCode.INVALID;
+ try {
+ dataTransferEventCode = DataTransferEventCode.values()[eventCode];
+ } catch (ArrayIndexOutOfBoundsException ignored) {
+ Log.e(TAG, "getDataTransferEventCode: invalid data transfer status from daemon");
+ }
+ return dataTransferEventCode;
+ }
+
+ private static DataTransferError getDataTransferError(Long errorCode) {
+ DataTransferError dataTransferError = DataTransferError.UNKNOWN;
+ if (errorCode == null) {
+ Log.e(TAG, "getDataTransferError: invalid error code");
+ } else {
+ try {
+ dataTransferError = DataTransferError.values()[errorCode.intValue()];
+ } catch (ArrayIndexOutOfBoundsException ignored) {
+ Log.e(TAG, "getDataTransferError: invalid data transfer error from daemon");
+ }
+ }
+ return dataTransferError;
+ }
}
\ No newline at end of file
diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/DaemonService.java b/ring-android/libringclient/src/main/java/cx/ring/services/DaemonService.java
index 6fced71..112db5d 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/services/DaemonService.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/services/DaemonService.java
@@ -42,7 +42,7 @@
public class DaemonService {
- private static final String TAG = DaemonService.class.getName();
+ private static final String TAG = DaemonService.class.getSimpleName();
private static final int POLLING_TIMEOUT = 50;
diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/DataTransferWrapper.java b/ring-android/libringclient/src/main/java/cx/ring/services/DataTransferWrapper.java
new file mode 100644
index 0000000..8556e14
--- /dev/null
+++ b/ring-android/libringclient/src/main/java/cx/ring/services/DataTransferWrapper.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2004-2018 Savoir-faire Linux Inc.
+ *
+ * Author: Pierre Duchemin <pierre.duchemin@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package cx.ring.services;
+
+import cx.ring.daemon.DataTransferInfo;
+import cx.ring.model.DataTransferError;
+
+public class DataTransferWrapper {
+
+ private DataTransferInfo dataTransferInfo;
+ private DataTransferError dataTransferError;
+
+ public DataTransferWrapper(DataTransferInfo dataTransferInfo, DataTransferError dataTransferError) {
+ this.dataTransferInfo = dataTransferInfo;
+ this.dataTransferError = dataTransferError;
+ }
+
+ public DataTransferInfo getDataTransferInfo() {
+ return dataTransferInfo;
+ }
+
+ public DataTransferError getDataTransferError() {
+ return dataTransferError;
+ }
+
+ public boolean isOutgoing() {
+ return this.dataTransferInfo.getFlags() == 0;
+ }
+ }
\ No newline at end of file