Search in sources :

Example 36 with MatrixError

use of org.matrix.androidsdk.core.model.MatrixError in project matrix-android-sdk by matrix-org.

the class MXMediaDownloadWorkerTask method doInBackground.

/**
 * Download and decode media in background.
 *
 * @param params
 * @return JsonElement if an error occurs
 */
@Override
protected JsonElement doInBackground(Void... params) {
    JsonElement jsonElementResult = null;
    MatrixError defaultError = new MatrixError();
    defaultError.errcode = MatrixError.UNKNOWN;
    try {
        URL url = new URL(mUrl);
        Log.d(LOG_TAG, "MXMediaDownloadWorkerTask " + this + " starts");
        mDownloadStats = new IMXMediaDownloadListener.DownloadStats();
        // don't known yet
        mDownloadStats.mEstimatedRemainingTime = -1;
        InputStream stream = null;
        int filelen = -1;
        HttpURLConnection connection = null;
        try {
            Proxy proxyConfig = mHsConfig.getProxyConfig();
            if (proxyConfig == null) {
                proxyConfig = Proxy.NO_PROXY;
            }
            connection = (HttpURLConnection) url.openConnection(proxyConfig);
            if (RestClient.getUserAgent() != null) {
                connection.setRequestProperty("User-Agent", RestClient.getUserAgent());
            }
            if (mHsConfig != null && connection instanceof HttpsURLConnection) {
                // Add SSL Socket factory.
                HttpsURLConnection sslConn = (HttpsURLConnection) connection;
                try {
                    Pair<SSLSocketFactory, X509TrustManager> pair = CertUtil.newPinnedSSLSocketFactory(mHsConfig);
                    sslConn.setSSLSocketFactory(pair.first);
                    sslConn.setHostnameVerifier(CertUtil.newHostnameVerifier(mHsConfig));
                } catch (Exception e) {
                    Log.e(LOG_TAG, "doInBackground SSL exception " + e.getMessage(), e);
                }
            }
            // add a timeout to avoid infinite loading display.
            float scale = (null != mNetworkConnectivityReceiver) ? mNetworkConnectivityReceiver.getTimeoutScale() : 1.0f;
            connection.setReadTimeout((int) (DOWNLOAD_TIME_OUT * scale));
            if (mIsAvScannerEnabled && null != mEncryptedFileInfo) {
                // POST the encryption info to let the av scanner decrypt and scan the content.
                connection.setRequestMethod("POST");
                connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
                connection.setDoOutput(true);
                connection.setUseCaches(false);
                EncryptedMediaScanBody encryptedMediaScanBody = new EncryptedMediaScanBody();
                encryptedMediaScanBody.encryptedFileInfo = mEncryptedFileInfo;
                String data = JsonUtility.getCanonicalizedJsonString(encryptedMediaScanBody);
                // Encrypt the data, if antivirus server supports it
                String publicServerKey = getAntivirusServerPublicKey();
                if (publicServerKey == null) {
                    // Error
                    throw new Exception("Unable to get public key");
                } else if (!TextUtils.isEmpty(publicServerKey)) {
                    OlmPkEncryption olmPkEncryption = new OlmPkEncryption();
                    olmPkEncryption.setRecipientKey(publicServerKey);
                    OlmPkMessage message = olmPkEncryption.encrypt(data);
                    EncryptedMediaScanEncryptedBody encryptedMediaScanEncryptedBody = new EncryptedMediaScanEncryptedBody();
                    encryptedMediaScanEncryptedBody.encryptedBodyFileInfo = new EncryptedBodyFileInfo(message);
                    data = JsonUtility.getCanonicalizedJsonString(encryptedMediaScanEncryptedBody);
                }
                // Else: no public key on this server, do not encrypt data
                OutputStream outputStream = connection.getOutputStream();
                try {
                    outputStream.write(data.getBytes("UTF-8"));
                } catch (Exception e) {
                    Log.e(LOG_TAG, "doInBackground Failed to serialize encryption info " + e.getMessage(), e);
                } finally {
                    outputStream.close();
                }
            }
            filelen = connection.getContentLength();
            stream = connection.getInputStream();
        } catch (Exception e) {
            Log.e(LOG_TAG, "bitmapForURL : fail to open the connection " + e.getMessage(), e);
            defaultError.error = e.getLocalizedMessage();
            // In case of 403, revert the key
            if (connection.getResponseCode() == HttpURLConnection.HTTP_FORBIDDEN && mMediaScanRestClient != null) {
                mMediaScanRestClient.resetServerPublicKey();
            }
            InputStream errorStream = connection.getErrorStream();
            if (null != errorStream) {
                try {
                    BufferedReader streamReader = new BufferedReader(new InputStreamReader(errorStream, "UTF-8"));
                    StringBuilder responseStrBuilder = new StringBuilder();
                    String inputStr;
                    while ((inputStr = streamReader.readLine()) != null) {
                        responseStrBuilder.append(inputStr);
                    }
                    jsonElementResult = new JsonParser().parse(responseStrBuilder.toString());
                } catch (Exception ee) {
                    Log.e(LOG_TAG, "bitmapForURL : Error parsing error " + ee.getMessage(), ee);
                }
            }
            // privacy
            // Log.d(LOG_TAG, "MediaWorkerTask " + mUrl + " does not exist");
            Log.d(LOG_TAG, "MediaWorkerTask an url does not exist");
            // (because the same url is used for all encrypted media when the av scanner is enabled).
            if (!mIsAvScannerEnabled || null == mEncryptedFileInfo) {
                synchronized (sUnreachableUrls) {
                    sUnreachableUrls.add(mUrl);
                }
            }
        }
        dispatchDownloadStart();
        // failed to open the remote stream without having exception
        if ((null == stream) && (null == jsonElementResult)) {
            jsonElementResult = new JsonParser().parse("Cannot open " + mUrl);
            // (because the same url is used for all encrypted media when the av scanner is enabled).
            if (!mIsAvScannerEnabled || null == mEncryptedFileInfo) {
                synchronized (sUnreachableUrls) {
                    sUnreachableUrls.add(mUrl);
                }
            }
        }
        // test if the download has not been cancelled
        if (!isDownloadCancelled() && (null == jsonElementResult)) {
            final long startDownloadTime = System.currentTimeMillis();
            String filename = buildFileName(mDownloadId, mMimeType) + ".tmp";
            FileOutputStream fos = new FileOutputStream(new File(mDirectoryFile, filename));
            mDownloadStats.mDownloadId = mDownloadId;
            mDownloadStats.mProgress = 0;
            mDownloadStats.mDownloadedSize = 0;
            mDownloadStats.mFileSize = filelen;
            mDownloadStats.mElapsedTime = 0;
            mDownloadStats.mEstimatedRemainingTime = -1;
            mDownloadStats.mBitRate = 0;
            // Publish progress every 100ms
            final Timer refreshTimer = new Timer();
            refreshTimer.scheduleAtFixedRate(new TimerTask() {

                @Override
                public void run() {
                    if (!mIsDone) {
                        updateAndPublishProgress(startDownloadTime);
                    }
                }
            }, new Date(), 100);
            try {
                byte[] buf = new byte[DOWNLOAD_BUFFER_READ_SIZE];
                int len;
                while (!isDownloadCancelled() && (len = stream.read(buf)) != -1) {
                    fos.write(buf, 0, len);
                    mDownloadStats.mDownloadedSize += len;
                }
                if (!isDownloadCancelled()) {
                    mDownloadStats.mProgress = 100;
                }
            } catch (OutOfMemoryError outOfMemoryError) {
                Log.e(LOG_TAG, "doInBackground: out of memory", outOfMemoryError);
                defaultError.error = outOfMemoryError.getLocalizedMessage();
            } catch (Exception e) {
                Log.e(LOG_TAG, "doInBackground fail to read image " + e.getMessage(), e);
                defaultError.error = e.getLocalizedMessage();
            }
            mIsDone = true;
            close(stream);
            fos.flush();
            fos.close();
            refreshTimer.cancel();
            if ((null != connection) && (connection instanceof HttpsURLConnection)) {
                connection.disconnect();
            }
            // the file has been successfully downloaded
            if (mDownloadStats.mProgress == 100) {
                try {
                    File originalFile = new File(mDirectoryFile, filename);
                    String newFileName = buildFileName(mDownloadId, mMimeType);
                    File newFile = new File(mDirectoryFile, newFileName);
                    if (newFile.exists()) {
                        // Or you could throw here.
                        mApplicationContext.deleteFile(newFileName);
                    }
                    originalFile.renameTo(newFile);
                } catch (Exception e) {
                    Log.e(LOG_TAG, "doInBackground : renaming error " + e.getMessage(), e);
                    defaultError.error = e.getLocalizedMessage();
                }
            }
        }
        if (mDownloadStats.mProgress == 100) {
            Log.d(LOG_TAG, "The download " + this + " is done.");
        } else {
            if (null != jsonElementResult) {
                Log.d(LOG_TAG, "The download " + this + " failed : mErrorAsJsonElement " + jsonElementResult.toString());
            } else {
                Log.d(LOG_TAG, "The download " + this + " failed.");
            }
        }
    } catch (Exception e) {
        Log.e(LOG_TAG, "Unable to download media " + this, e);
        defaultError.error = e.getMessage();
    }
    // build a JSON from the error
    if (!TextUtils.isEmpty(defaultError.error)) {
        jsonElementResult = JsonUtils.getGson(false).toJsonTree(defaultError);
    }
    // remove the task from the loading one
    synchronized (sPendingDownloadById) {
        sPendingDownloadById.remove(mDownloadId);
    }
    return jsonElementResult;
}
Also used : EncryptedBodyFileInfo(org.matrix.androidsdk.crypto.model.crypto.EncryptedBodyFileInfo) OutputStream(java.io.OutputStream) FileOutputStream(java.io.FileOutputStream) EncryptedMediaScanEncryptedBody(org.matrix.androidsdk.rest.model.EncryptedMediaScanEncryptedBody) URL(java.net.URL) Proxy(java.net.Proxy) HttpURLConnection(java.net.HttpURLConnection) EncryptedMediaScanBody(org.matrix.androidsdk.rest.model.EncryptedMediaScanBody) TimerTask(java.util.TimerTask) SSLSocketFactory(javax.net.ssl.SSLSocketFactory) OlmPkEncryption(org.matrix.olm.OlmPkEncryption) JsonParser(com.google.gson.JsonParser) InputStreamReader(java.io.InputStreamReader) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) OlmPkMessage(org.matrix.olm.OlmPkMessage) FileNotFoundException(java.io.FileNotFoundException) Date(java.util.Date) Timer(java.util.Timer) JsonElement(com.google.gson.JsonElement) IMXMediaDownloadListener(org.matrix.androidsdk.listeners.IMXMediaDownloadListener) X509TrustManager(javax.net.ssl.X509TrustManager) FileOutputStream(java.io.FileOutputStream) BufferedReader(java.io.BufferedReader) MatrixError(org.matrix.androidsdk.core.model.MatrixError) File(java.io.File) HttpsURLConnection(javax.net.ssl.HttpsURLConnection)

Example 37 with MatrixError

use of org.matrix.androidsdk.core.model.MatrixError in project matrix-android-sdk by matrix-org.

the class MatrixMessageListFragment method add.

/**
 * Add a media item in the room.
 */
private void add(final RoomMediaMessage roomMediaMessage) {
    MessageRow messageRow = addMessageRow(roomMediaMessage);
    // add sanity check
    if (null == messageRow) {
        return;
    }
    final Event event = messageRow.getEvent();
    if (!event.isUndelivered()) {
        ApiCallback<Void> callback = new ApiCallback<Void>() {

            @Override
            public void onSuccess(Void info) {
                getUiHandler().post(new Runnable() {

                    @Override
                    public void run() {
                        onMessageSendingSucceeded(event);
                    }
                });
            }

            private void commonFailure(final Event event) {
                getUiHandler().post(new Runnable() {

                    @Override
                    public void run() {
                        Activity activity = getActivity();
                        if (null != activity) {
                            // display the error message only if the message cannot be resent
                            if ((null != event.unsentException) && (event.isUndelivered())) {
                                if (event.unsentException instanceof IOException) {
                                    Toast.makeText(activity, activity.getString(R.string.unable_to_send_message) + " : " + activity.getString(R.string.network_error), Toast.LENGTH_LONG).show();
                                } else {
                                    Toast.makeText(activity, activity.getString(R.string.unable_to_send_message) + " : " + event.unsentException.getLocalizedMessage(), Toast.LENGTH_LONG).show();
                                }
                            } else if (null != event.unsentMatrixError) {
                                String localised = (event.unsentMatrixError instanceof MXCryptoError) ? ((MXCryptoError) event.unsentMatrixError).getDetailedErrorDescription() : event.unsentMatrixError.getLocalizedMessage();
                                Toast.makeText(activity, activity.getString(R.string.unable_to_send_message) + " : " + localised, Toast.LENGTH_LONG).show();
                            }
                            mAdapter.notifyDataSetChanged();
                            onMessageSendingFailed(event);
                        }
                    }
                });
            }

            @Override
            public void onNetworkError(final Exception e) {
                commonFailure(event);
            }

            @Override
            public void onMatrixError(final MatrixError e) {
                // do not display toast if the sending failed because of unknown device (e2e issue)
                if (event.mSentState == Event.SentState.FAILED_UNKNOWN_DEVICES) {
                    getUiHandler().post(new Runnable() {

                        @Override
                        public void run() {
                            mAdapter.notifyDataSetChanged();
                            onUnknownDevices(event, (MXCryptoError) e);
                        }
                    });
                } else if (MatrixError.M_CONSENT_NOT_GIVEN.equals(e.errcode)) {
                    getUiHandler().post(new Runnable() {

                        @Override
                        public void run() {
                            mAdapter.notifyDataSetChanged();
                            onConsentNotGiven(event, e);
                        }
                    });
                } else {
                    commonFailure(event);
                }
            }

            @Override
            public void onUnexpectedError(final Exception e) {
                commonFailure(event);
            }
        };
        roomMediaMessage.setEventSendingCallback(callback);
    }
}
Also used : SimpleApiCallback(org.matrix.androidsdk.core.callback.SimpleApiCallback) ApiCallback(org.matrix.androidsdk.core.callback.ApiCallback) Activity(android.app.Activity) IOException(java.io.IOException) IOException(java.io.IOException) MessageRow(org.matrix.androidsdk.adapters.MessageRow) MotionEvent(android.view.MotionEvent) Event(org.matrix.androidsdk.rest.model.Event) MatrixError(org.matrix.androidsdk.core.model.MatrixError) MXCryptoError(org.matrix.androidsdk.crypto.MXCryptoError)

Example 38 with MatrixError

use of org.matrix.androidsdk.core.model.MatrixError in project matrix-android-sdk by matrix-org.

the class MatrixMessageListFragment method requestSearchHistory.

/**
 * Search the pattern on a pagination server side.
 */
public void requestSearchHistory() {
    // there is no more server message
    if (TextUtils.isEmpty(mNextBatch)) {
        mIsBackPaginating = false;
        return;
    }
    mIsBackPaginating = true;
    final int firstPos = mMessageListView.getFirstVisiblePosition();
    final String fPattern = mPattern;
    final int countBeforeUpdate = mAdapter.getCount();
    showLoadingBackProgress();
    List<String> roomIds = null;
    if (null != mRoom) {
        roomIds = Arrays.asList(mRoom.getRoomId());
    }
    ApiCallback<SearchResponse> callback = new ApiCallback<SearchResponse>() {

        @Override
        public void onSuccess(final SearchResponse searchResponse) {
            // check that the pattern was not modified before the end of the search
            if (TextUtils.equals(mPattern, fPattern)) {
                List<SearchResult> searchResults = searchResponse.searchCategories.roomEvents.results;
                // is there any result to display
                if (0 != searchResults.size()) {
                    mAdapter.setNotifyOnChange(false);
                    for (SearchResult searchResult : searchResults) {
                        MessageRow row = new MessageRow(searchResult.result, (null == mRoom) ? null : mRoom.getState());
                        mAdapter.insert(row, 0);
                    }
                    mNextBatch = searchResponse.searchCategories.roomEvents.nextBatch;
                    // Scroll the list down to where it was before adding rows to the top
                    getUiHandler().post(new Runnable() {

                        @Override
                        public void run() {
                            final int expectedFirstPos = firstPos + (mAdapter.getCount() - countBeforeUpdate);
                            // trick to avoid that the list jump to the latest item.
                            mMessageListView.lockSelectionOnResize();
                            mAdapter.notifyDataSetChanged();
                            // do not use count because some messages are not displayed
                            // so we compute the new pos
                            mMessageListView.setSelection(expectedFirstPos);
                            mMessageListView.post(new Runnable() {

                                @Override
                                public void run() {
                                    mIsBackPaginating = false;
                                    // fill the history
                                    if (mMessageListView.getFirstVisiblePosition() <= 2) {
                                        requestSearchHistory();
                                    }
                                }
                            });
                        }
                    });
                } else {
                    mIsBackPaginating = false;
                }
                hideLoadingBackProgress();
            }
        }

        private void onError() {
            mIsBackPaginating = false;
            hideLoadingBackProgress();
        }

        // the request will be auto restarted when a valid network will be found
        @Override
        public void onNetworkError(Exception e) {
            Log.e(LOG_TAG, "Network error: " + e.getMessage(), e);
            onError();
        }

        @Override
        public void onMatrixError(MatrixError e) {
            Log.e(LOG_TAG, "Matrix error" + " : " + e.errcode + " - " + e.getMessage());
            onError();
        }

        @Override
        public void onUnexpectedError(Exception e) {
            Log.e(LOG_TAG, "onUnexpectedError error" + e.getMessage(), e);
            onError();
        }
    };
    if (mIsMediaSearch) {
        mSession.searchMediaByName(mPattern, roomIds, mNextBatch, callback);
    } else {
        mSession.searchMessagesByText(mPattern, roomIds, mNextBatch, callback);
    }
}
Also used : SimpleApiCallback(org.matrix.androidsdk.core.callback.SimpleApiCallback) ApiCallback(org.matrix.androidsdk.core.callback.ApiCallback) SearchResult(org.matrix.androidsdk.rest.model.search.SearchResult) IOException(java.io.IOException) SearchResponse(org.matrix.androidsdk.rest.model.search.SearchResponse) MessageRow(org.matrix.androidsdk.adapters.MessageRow) MatrixError(org.matrix.androidsdk.core.model.MatrixError)

Example 39 with MatrixError

use of org.matrix.androidsdk.core.model.MatrixError in project matrix-android-sdk by matrix-org.

the class MatrixMessageListFragment method onPaginateRequestError.

// ==============================================================================================================
// pagination methods
// ==============================================================================================================
/**
 * Manage the request history error cases.
 *
 * @param error the error object.
 */
private void onPaginateRequestError(final Object error) {
    Activity activity = getActivity();
    if (null != activity) {
        if (error instanceof Exception) {
            Log.e(LOG_TAG, "Network error: " + ((Exception) error).getMessage(), (Exception) error);
            Toast.makeText(activity, activity.getString(R.string.network_error), Toast.LENGTH_SHORT).show();
        } else if (error instanceof MatrixError) {
            final MatrixError matrixError = (MatrixError) error;
            Log.e(LOG_TAG, "Matrix error" + " : " + matrixError.errcode + " - " + matrixError.getMessage());
            Toast.makeText(activity, activity.getString(R.string.matrix_error) + " : " + matrixError.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
        }
        hideLoadingBackProgress();
        hideLoadingForwardProgress();
        Log.d(LOG_TAG, "requestHistory failed " + error);
        mIsBackPaginating = false;
    }
}
Also used : Activity(android.app.Activity) MatrixError(org.matrix.androidsdk.core.model.MatrixError) IOException(java.io.IOException)

Example 40 with MatrixError

use of org.matrix.androidsdk.core.model.MatrixError in project matrix-android-sdk by matrix-org.

the class GroupsManager method onJoinGroup.

/**
 * Manage the group joining.
 *
 * @param groupId the group id
 * @param notify  true to notify
 */
public void onJoinGroup(final String groupId, final boolean notify) {
    Group group = getGroup(groupId);
    if (null == group) {
        group = new Group(groupId);
    }
    if (TextUtils.equals(RoomMember.MEMBERSHIP_JOIN, group.getMembership())) {
        Log.d(LOG_TAG, "## onJoinGroup() : the group " + groupId + " was already joined");
        return;
    }
    group.setMembership(RoomMember.MEMBERSHIP_JOIN);
    mStore.storeGroup(group);
    // try retrieve  the summary
    mGroupsRestClient.getGroupSummary(groupId, new ApiCallback<GroupSummary>() {

        /**
         * Common method
         */
        private void onDone() {
            if (notify) {
                mDataHandler.onJoinGroup(groupId);
            }
        }

        @Override
        public void onSuccess(GroupSummary groupSummary) {
            Group group = getGroup(groupId);
            if (null != group) {
                group.setGroupSummary(groupSummary);
                mStore.flushGroup(group);
                onDone();
                if (null != mPendingJoinGroups.get(groupId)) {
                    mPendingJoinGroups.get(groupId).onSuccess(null);
                    mPendingJoinGroups.remove(groupId);
                }
            }
        }

        @Override
        public void onNetworkError(Exception e) {
            Log.e(LOG_TAG, "## onJoinGroup() : failed " + e.getMessage(), e);
            onDone();
            if (null != mPendingJoinGroups.get(groupId)) {
                mPendingJoinGroups.get(groupId).onNetworkError(e);
                mPendingJoinGroups.remove(groupId);
            }
        }

        @Override
        public void onMatrixError(MatrixError e) {
            Log.e(LOG_TAG, "## onMatrixError() : failed " + e.getMessage());
            onDone();
            if (null != mPendingJoinGroups.get(groupId)) {
                mPendingJoinGroups.get(groupId).onMatrixError(e);
                mPendingJoinGroups.remove(groupId);
            }
        }

        @Override
        public void onUnexpectedError(Exception e) {
            Log.e(LOG_TAG, "## onUnexpectedError() : failed " + e.getMessage(), e);
            onDone();
            if (null != mPendingJoinGroups.get(groupId)) {
                mPendingJoinGroups.get(groupId).onUnexpectedError(e);
                mPendingJoinGroups.remove(groupId);
            }
        }
    });
}
Also used : Group(org.matrix.androidsdk.rest.model.group.Group) GroupSummary(org.matrix.androidsdk.rest.model.group.GroupSummary) MatrixError(org.matrix.androidsdk.core.model.MatrixError)

Aggregations

MatrixError (org.matrix.androidsdk.core.model.MatrixError)41 SimpleApiCallback (org.matrix.androidsdk.core.callback.SimpleApiCallback)15 ApiCallback (org.matrix.androidsdk.core.callback.ApiCallback)14 ArrayList (java.util.ArrayList)12 MXDeviceInfo (org.matrix.androidsdk.crypto.data.MXDeviceInfo)9 IOException (java.io.IOException)7 HashMap (java.util.HashMap)7 List (java.util.List)7 Room (org.matrix.androidsdk.data.Room)7 Event (org.matrix.androidsdk.rest.model.Event)7 CountDownLatch (java.util.concurrent.CountDownLatch)6 MXDecryptionException (org.matrix.androidsdk.crypto.MXDecryptionException)6 MXUsersDevicesMap (org.matrix.androidsdk.crypto.data.MXUsersDevicesMap)6 JsonObject (com.google.gson.JsonObject)5 MXCryptoError (org.matrix.androidsdk.crypto.MXCryptoError)4 JsonElement (com.google.gson.JsonElement)3 MXSession (org.matrix.androidsdk.MXSession)3 MXOlmSessionResult (org.matrix.androidsdk.crypto.data.MXOlmSessionResult)3 RoomMember (org.matrix.androidsdk.rest.model.RoomMember)3 Activity (android.app.Activity)2