Slack Real-Time-Messaging websocket - android

Trying to implement this in application. Slack RTM
After call to rtm.start I get JSON-response and extract wss url. After it, following documentation I need to open websocket.
Tried two libraries
compile 'com.koushikdutta.async:androidasync:2.+'
compile 'org.java-websocket:Java-WebSocket:1.3.0'
First gives TimeoutException, second - enters onClose method with i = -1, b = true (onError or onOpen are not called, see code below).
connection = (HttpURLConnection) new URL(getQuery(URL + "rtm.start",
new Pair<>("token", TOKEN))).openConnection();
final String response = readIs(connection.getInputStream());
JSONObject jResponse = new JSONObject(response);
String uri = (String) jResponse.get("url");
With Java-WebSocket I've tried this code (standard from example on github):
connectWebSocket(uri);
private void connectWebSocket(String uriStr) {
URI uri;
try {
uri = new URI(uriStr);
} catch (URISyntaxException e) {
e.printStackTrace();
return;
}
log(uri.toString());
log(uri.toASCIIString());
mWebSocketClient = new WebSocketClient(uri) {
#Override
public void onOpen(ServerHandshake serverHandshake) {
log("Opened");
mWebSocketClient.send("Hello from " + Build.MANUFACTURER + " " + Build.MODEL);
}
#Override
public void onMessage(String s) {
log(s);
}
#Override
public void onClose(int i, String s, boolean b) {
log("Closed " + s + " " + b + " number: " + i);
}
#Override
public void onError(Exception e) {
log("Error " + e.getMessage());
}
};
mWebSocketClient.connect();
}
As I've said above - only onClose is called.
With AndroidAsync tried standard code from example too:
AsyncHttpClient.getDefaultInstance().websocket(uri, "wss", (ex, webSocket) -> {
if (ex != null) {
log(ex.getMessage());
return;
}
webSocket.send("a string");
});
I've never worked with websockets on android before, and can't understand what am I doing wrong. Will appreciate your help.
Url in JSON is of type of
wss://ms156.slack-msgs.com/websocket/LYBUMUtG-bqj9HkKwEB5Yk_DCyPeRbnZ4viUJYHzrzJnLr-M74d46IQ9khTF8rik-v6ckJ4hqXPRi666hyPR6pismYBZBsggJUade3LOARc=

Finally my coleague managed to open this socket using OkHttp. If somebody is interested - code of test project is provided below:
http://pastebin.com/3YhLjAn7
What is interesting - in the end we decided not to use RTM, because load for one connection is too high - you receive events from all chats and there is no way to set filter only for one specific.

Related

Android Printing using custom Print service

I am trying to write a custom android print service. I have followed the instruction mentioned in the below blog:
https://github.com/zaki50/MyPrintServiceProject
I am able to create a service, which executes a print job. But after the job doesn't print any thing. My question is, what is the localId that we should provide. Is it printer ip, name? Also is there any way to know why the print job doesn't work.
Basically the two methods that I am concerned about are adding onStartPrinterDiscovery and OnPrintJobQueue as mentioned below:
#Override
public void onStartPrinterDiscovery(List<PrinterId> priorityList) {
String str = Settings.Secure.getString(getBaseContext().getContentResolver(), "enabled_print_services");
Log.d("myprinter", "PrinterDiscoverySession#onStartPrinterDiscovery(priorityList: " + priorityList + ") called")
final List<PrinterInfo> printers = new ArrayList<>();
final PrinterId printerId = generatePrinterId("D8:49:2F:64:04:DB");
final PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, "D8:49:2F:64:04:DB", PrinterInfo.STATUS_IDLE);
PrinterCapabilitiesInfo.Builder capBuilder = new PrinterCapabilitiesInfo.Builder(printerId);
capBuilder.addMediaSize(PrintAttributes.MediaSize.NA_LETTER, true);
capBuilder.addMediaSize(PrintAttributes.MediaSize.NA_LETTER, false);
capBuilder.addResolution(new PrintAttributes.Resolution("resolutionId", "default resolution", 600, 600), true);
capBuilder.setColorModes(PrintAttributes.COLOR_MODE_COLOR | PrintAttributes.COLOR_MODE_MONOCHROME, PrintAttributes.COLOR_MODE_COLOR);
builder.setCapabilities(capBuilder.build());
printers.add(builder.build());
addPrinters(printers);
}
#Override
protected void onPrintJobQueued(PrintJob printJob) {
Log.d("myprinter", "queued: " + printJob.getId().toString());
printJob.start();
//printJob.complete();
final PrintDocument document = printJob.getDocument();
final FileInputStream in = new FileInputStream(document.getData().getFileDescriptor());
try {
final byte[] buffer = new byte[4];
#SuppressWarnings("unused")
final int read = in.read(buffer);
Log.d("myprinter", "first " + buffer.length + "bytes of content: " + toString(buffer));
} catch (IOException e) {
Log.d("myprinter", "", e);
} finally {
try {
in.close();
} catch (IOException e) {
assert true;
}
}
if( printJob.isStarted()){
printJob.complete();
}
}
My Question is what should be printerId(or localId). How do we know if the printjob has succeeded or failed
You can do detection of print job status with other methods in the class:
if( printJob.isStarted() ){
}
else if( printJob.isCompleted() ){
}
else if( printJob.isCancelled() ){
}
else if( printJob.isFailed() ){
}
In addition, the print service has it's own methods listed in the docs:
#Override
protected void onPrintJobQueued(PrintJob printJob) {
Log.d("printer", "queued: " + printJob.getId().toString());
printJob.start();
//...
printJob.complete();
}
#Override
protected void onRequestCancelPrintJob(PrintJob printJob) {
Log.d("printer", "canceled: " + printJob.getId().toString());
printJob.cancel();
}

What should we use for downloading large files from remote server. Service? IntentService? AsyncTask? Thread? or something else in android?

I am new to android, I have gone through many of the forums and discussions but still I am confused about what should I use for downloading large files from server!
In our App we are playing multiple videos in a playlist on the app frontend and meanwhile we are calling API service to get list videos in playlist, we are calling the API within an asynctask and onpostexecute method parse the API response and queue any new files to download in the downloadmanger.
The points of concern
Is using asynctask for fetching response from remote API enough? or is there any better option for us?
Calling download manager from main is a bad practice as I understand from reading, then whats the best way to go (Service, IntentService, Thread or AsyncTask)? What will be the difference of using Service, IntentService, Thread or AsyncTask in this scenario.
Can we execute the download when the app is kickedoff when in case of incoming call or user clicks home button, so the download should still continue and don't waste bandwidth, memory etc used for already downloaded part.
Can we initiate a download even if the app is in background?
Should we do the database operations in a different thread, is it the best practice?
public class MediaAsyncTask extends AsyncTask>
{
#Override
protected List<Media> doInBackground(String... params) {
List<Media> result = new ArrayList<Media>();
try {
ResponseHandler responseHandlerObj = new ResponseHandler(getApplicationContext());
result = responseHandlerObj.deviceMedia(device_id);
media_status = responseHandlerObj.getResponse_status();
media_msg = responseHandlerObj.getResponse_msg();
media_version = responseHandlerObj.getMedia_version();
medias_total = responseHandlerObj.getMedias_total();
} catch (Exception e) {
Log.d(TAG, e.getLocalizedMessage());
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(List<Media> result) {
Log.e(TAG, "status " + media_status);
if (media_status.equals(STATUS_SUCCESS)) {
Log.d(TAG, media_msg);
if (device_path != null) {
int _total_downloaded = databaseHandler.getDownloadedMediaCount(device_id);
int _total_in_api = medias_total;
int _downloaded_version = preferenceHelper.getDeviceMediaVersion(device_id);
Log.d(TAG, "media_version : " + media_version + " _downloaded_version : " + _downloaded_version + " _total_downloaded : " + _total_downloaded + " _total_in_api : " + _total_in_api);
//remove true after testing
if (media_version != _downloaded_version || _total_downloaded != _total_in_api) {
databaseHandler.deleteAllDeviceMedias(device_id);
int id;
String file;
for (Media media : result) {
id = 0;
file = media.getFile();
String file_url = media.getFile_url();
Log.d(TAG, "media file exists: " + fileManager.checkFileExists(device_path, file));
if (file != null && !fileManager.checkFileExists(device_path, file) && URLUtil.isValidUrl(file_url)) {
media.setDownloaded(0);
id = databaseHandler.saveMedia(media);
queueDownload(file_url, file);
} else if (fileManager.checkFileExists(device_path, file)) {
long app_size = (int) fileManager.getFileSize(device_path + "/" + file);
long server_size = media.getFile_size();
long server_size_minus = server_size - 100;
if (app_size < server_size_minus) {
fileManager.deleteFile(device_path + "/" + file);
queueDownload(file_url, file);
} else {
id = saveDownloadedResource(media);
}
}
}
}
if (download_files.size() == 0) {
Log.d(TAG, "nothing to download");
preferenceHelper.setDeviceMediaVersion(device_id, media_version);
}
}
} else {
Log.e(TAG, "Media: Failed to fetch data!");
}
}
private int saveDownloadedResource(Media media) {
int id = 0;
media.setDownloaded(1);
id = databaseHandler.saveMedia(media);
initUpdateLayoutOnNewResource();
return id;
}
}

How to implement connection failover in client side

I am trying to implement connection failover in android application. Basically I have list of URLs which application connect using websocket, In case of unable to connect with any url I need to try a second connection. API which I am using to connect with websocket in android side is not synchronous. so when I start connect to websocket after executing this method I dont know either connection establish or not until OnOpen method called and then I set some boolean there to use further.
What I tried: One solution in my mind is to start to call connect method from a thread and sleep this for certain time if OnOpen method called within timespan is ok otherwise try to use second connection url.
Can someone give me hint how I can resolve this. Here is a sample code (without thread implementation):
private DataUploader() {
// test list of url
urlList = new ArrayList<String>();
urlList.add("192.168.220.197:9001/observation/");
urlList.add("192.168.220.197:9002/observation/");
urlList.add("echo.websocket.org");
connectWebSocket();
}
public void connectWebSocket() {
if (urlList.size() > -1) {
String url = urlList.get(index);
this.connect(url);
index++;
}
}
private void connect(String websocketEndPointUrl) {
URI uri;
try {
websocketEndPointUrl = "ws://" + websocketEndPointUrl;
uri = new URI(websocketEndPointUrl);
} catch (URISyntaxException e) {
e.printStackTrace();
return;
}
mWebSocketClient = new WebSocketClient(uri) {
#Override
public void onOpen(ServerHandshake serverHandshake) {
Log.i("Websocket", "Opened");
isReady = true;
}
#Override
public void onMessage(String s) {
///
}
#Override
public void onClose(int i, String s, boolean b) {
Log.i("Websocket", "Closed " + s);
}
#Override
public void onError(Exception e) {
Log.i("Websocket", "Error " + e.getMessage());
}
};
mWebSocketClient.connect();
}

ownCloud Android DownloadRemoteFile File Name

I'm trying to download a list of RemoteFiles in Android using ownCloud. I can download the files perfectly fine but I'd like to notify the user when a file finishes. I'm downloading an entire directory:
#Override
public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
if (operation instanceof ReadRemoteFolderOperation) {
if (result.isSuccess()) {
Toast.makeText(this, "Finished reading folder", Toast.LENGTH_SHORT).show();
for (Object o : result.getData()) {
RemoteFile remoteFile = (RemoteFile) o;
String remotePath = remoteFile.getRemotePath();
File targetDirectory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/owncloud_download");
downloadHelper.downloadFile(remoteFile, targetDirectory);
}
}
}
if (operation instanceof DownloadRemoteFileOperation) {
if (result.isSuccess()) {
// Notify the user here that the file finished
}
}
}
I've looked at the ownCloud library source but can't seem to find what a DownloadRemoteFileOperation returns as a result other than a boolean indicating success and an HTTP status code. I thought it might be in result.getLogMessage() but that just gives me an HTTP 200 status. How can I get the name of a file that's finished?
Edit: I also looked at result.getData() but that's null in a DownloadRemoteFileOperation.
Here's my workaround for the time being. I didn't want to modify the ownCloud library source (again) so instead I just do a check in onTransferProgress like so:
#Override
public void onTransferProgress(long rate, long transferred, long total, String fileName) {
if (transferred == total) {
runOnUiThread(new Runnable() {
// do the update here, file name is available
}
}
}
Here's another option. I needed the file being uploaded if the upload failed so I modified the ownCloud library source. This way I could return file names in the RemoteOperationResult.
RemoteOperationResult.java:
private String fileName;
public String getFileName() {
return fileName;
}
public void setFileName(String name) {
fileName = name;
}
DownloadRemoteFileOperation.java
#Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
/// download will be performed to a temporal file, then moved to the final location
File tmpFile = new File(getTmpPath());
/// perform the download
try {
tmpFile.getParentFile().mkdirs();
int status = downloadFile(client, tmpFile);
result = new RemoteOperationResult(isSuccess(status), status,
(mGet != null ? mGet.getResponseHeaders() : null));
Log_OC.i(TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " +
result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " +
result.getLogMessage(), e);
}
// Added this line
result.setFileName(mRemotePath);
return result;
}
UploadRemoteFileOperation.java:
#Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
try {
// / perform the upload
synchronized (mCancellationRequested) {
if (mCancellationRequested.get()) {
throw new OperationCancelledException();
} else {
mPutMethod = new PutMethod(client.getWebdavUri() +
WebdavUtils.encodePath(mRemotePath));
}
}
int status = uploadFile(client);
if (mForbiddenCharsInServer){
result = new RemoteOperationResult(
RemoteOperationResult.ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER);
} else {
result = new RemoteOperationResult(isSuccess(status), status,
(mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
}
} catch (Exception e) {
// TODO something cleaner with cancellations
if (mCancellationRequested.get()) {
result = new RemoteOperationResult(new OperationCancelledException());
} else {
result = new RemoteOperationResult(e);
}
}
// Added this line
result.setFileName(mLocalPath);
return result;
}

Android - Autobahn web socket communication

I am working on Web socket communication with Autobahn library.
The problem I have is after connecting server, then message should be sent without connection again. But the message is sent with different connection that it connects to server every single time to send a message.
public class WebSocket_Connector extends Activity{
private static final String TAG = "ECHOCLIENT";
private static final String TAG1 = "My app";
public final WebSocketConnection mConnection = new WebSocketConnection();
private String tmpString = "";
public void connect(final String wsuri) {
Log.d(TAG, "Connecting to: " + wsuri);
try {
mConnection.connect(wsuri, new WebSocketHandler() {
#Override
public void onOpen() {
Log.d(TAG, "Status: Connected to " + wsuri );
Log.d(TAG, "Connection successful!\n");
mConnection.sendTextMessage(tmpString);
tmpString = "";
}
#Override
public void onTextMessage(String payload) {
Log.d(TAG, "Got echo: " + payload);
}
#Override
public void onClose(int code, String reason) {
Log.d(TAG, "Connection closed.");
}
});
} catch (WebSocketException e) {
Log.d(TAG, e.toString());
}
}
public void sendMessage(String message) {
if (mConnection.isConnected()) {
Log.d(TAG1, "Messeage is sent : " + message);
mConnection.sendTextMessage(message);
}
else {
tmpString = message;
connect("ws://192.168.3.100:7681");
}
}
}
This is the code I have, and...When you see "sendMessage" method, it always goes to 'else' not, if loop. Any suggestion 'experts' please..?
i don't know the package name you are dealing with for websocket. So first it has to be provided to get reliable answer to your question. But let say if it is something similar to :
https://code.google.com/p/weberknecht/source/browse/trunk/src/main/de/roderick/weberknecht/WebSocketConnection.java?r=2
note: i have not seen there isConnected() method but assume that it is added somewhere else.
you can see from source that onOpen() (line 88) is called before connected = true; on line (91). if this member var will be used as result of isConnected() then your code always will follow "else" part of the condition.
i would advice to dig into websocket api and its usage pattern further.

Categories

Resources