Simple SignalR Android Example Issue - android

I am basically trying to send a message from my android to my server and the server to send back a response to my android app. I followed THIS tutorial.
Just a simple exercise to introduce myself in to SignalR using Azure Web API and Android.
My Complete Server code in C#:
public class TestHub: Hub {
public void SendMessage(string name, string message) {
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(name, message);
}
public void SendClientMessage(CustomType obj) {
Clients.All.broadcastMessage("From Server", "Server got the message bro");
}
public class CustomType {
public string Name;
public int Id;
}
}
Complete Android Java code:
public class MainActivity extends AppCompatActivity {
Handler handler;
TextView statustext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
statustext = (TextView) findViewById(R.id.status);
Platform.loadPlatformComponent(new AndroidPlatformComponent());
// Change to the IP address and matching port of your SignalR server.
String host = "https://My-Service-name.azure-mobile.net/";
HubConnection connection = new HubConnection(host);
HubProxy hub = connection.createHubProxy("TestHub");
SignalRFuture < Void > awaitConnection = connection.start();
try {
awaitConnection.get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
hub.subscribe(this);
try {
hub.invoke("SendMessage", "Client", "Hello Server!").get();
hub.invoke("SendClientMessage",
new CustomType() {
{
Name = "Android Homie";
Id = 42;
}
}).get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
}
//I have no idea what the following method is for. Just followed the tutorial.. (blindly)
public void UpdateStatus(String status) {
final String fStatus = status;
handler.post(new Runnable() {
#Override
public void run() {
statustext.setText(fStatus);
}
});
}
public class CustomType {
public String Name;
public int Id;
}
}
Problems with this:
1. I get an exception:
java.util.concurrent.ExecutionException:
microsoft.aspnet.signalr.client.transport.NegotiationException: There
was a problem in the negotiation with the server
2. I feel like I haven't properly called the server from the Java code.
Should the URL be:
https://My-Service-name.azure-mobile.net/
or
https://My-Service-name.azure-mobile.net/api/signalr
Can someone clarify these doubts and help me set it up?

Related

Android and Java Ping/Pong Web Socket functionality

I have developed and Android application with is connecting to JAVA Web Socket and basically it is working very well.
The issue is, that sometimes the client is disconnected but connection at the server side is appearing to be connected.
I try to investigate, when and why it happened but unfortunately i could not find the a specific scenario that cause to this problem.
I have thought to implement Ping/Pong messaging between server and all clients and in case that there is no answer from the clients is to closed the connection at the server side.
i can easily implement such my private mechanism but I have read around and I understand that Java and Android has an build in Ping/Pong messaging mechanism but i was not able to find any example of that.
Can anyway, provide a simple example how to implement Ping/Pong messaging functionality using the build in tools?
I have succeed to implement Ping/Pong functionality between EE JAVA WebSocket and android application. The server is sending Ping message to client every 5 min. if server does not got Pong message back within 5 second, the server is closing client connection.
here is my solution if someone will need it:
WebSocket side:
public class User {
public ScheduledExecutorService pingExecutorService;
public Timer disconnectTimer;
private Session userSession;
private String userName;
public User(Session userSession) {
this.userSession = userSession;
}
public Session getUserSession() {
return userSession;
}
public void setUserSession(Session userSession) {
this.userSession = userSession;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
#OnOpen
public void onOpen(Session session) {
User newUserConnection = new User(session);
connections.getConnections().put(session.getId(), newUserConnection);
schedulePingMessages(newUserConnection);
}
#OnClose
public void onClose(Session session) {
handleOnClose(session);
}
#OnMessage
public void onMessage(String message, Session session) {
messageHandler.handleMessage(message, session);
}
#OnMessage
public void onPong(PongMessage pongMessage, Session session) {
String sourceSessionId = session.getId();
User user = connections.getConnections().get(sourceSessionId);
user.disconnectTimer.cancel();
user.disconnectTimer.purge();
}
#OnError
public void onError(Throwable t) {
System.out.println(new Date() + "onError::" + t.getMessage());
t.printStackTrace();
}
private void schedulePingMessages(User newUserConnection) {
newUserConnection.pingExecutorService = Executors.newScheduledThreadPool(1);
newUserConnection.pingExecutorService.scheduleAtFixedRate(() -> {
scheduleDiconnection(newUserConnection);
try {
String data = "Ping";
ByteBuffer payload = ByteBuffer.wrap(data.getBytes());
newUserConnection.getUserSession().getBasicRemote().sendPing(payload);
} catch (IOException e) {
e.printStackTrace();
}
}, 300, 300, TimeUnit.SECONDS);
}
private void scheduleDiconnection(User user) {
user.disconnectTimer = new Timer();
user.disconnectTimer.schedule(new TimerTask() {
#Override
public void run() {
try {
user.getUserSession().close(new CloseReason(CloseCodes.UNEXPECTED_CONDITION," Client does not response"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, 5000);
}
The android side just need to add the following override method:
#Override
public void onWebsocketPing(WebSocket conn, Framedata f) {
Log.i("ZCF","got Ping !");
super.onWebsocketPing(conn, f);
}

IBM Watson Tone Analyzer Gives Empty Response

I am using Tone Analyzer of IBM Watson in my Android Code,but i keep getting java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
Following is my code
public class MainActivity extends AppCompatActivity {
final ToneAnalyzer toneAnalyzer =
new ToneAnalyzer("2018-01-19");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
JSONObject credentials = null; // Convert the file into a JSON object
try {
credentials = new JSONObject(IOUtils.toString(
getResources().openRawResource(R.raw.credentials), "UTF-8"
));
String username = credentials.getString("username");
String password = credentials.getString("password");
toneAnalyzer.setUsernameAndPassword(username, password);
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Button analyzeButton = (Button)findViewById(R.id.analyze_button);
analyzeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
EditText userInput = (EditText)findViewById(R.id.user_input);
final String textToAnalyze = userInput.getText().toString();
ToneOptions options = new ToneOptions.Builder()
.addTone(Tone.EMOTION)
.html(false).build();
toneAnalyzer.getTone(textToAnalyze, options).enqueue(
new ServiceCallback<ToneAnalysis>() {
#Override
public void onResponse(ToneAnalysis response) {
Log.i("Hii", "onResponse: "+response.getDocumentTone());
List<ToneScore> scores = response.getDocumentTone()
.getTones()
.get(0)
.getTones();
String detectedTones = "";
for(ToneScore score:scores) {
if(score.getScore() > 0.5f) {
detectedTones += score.getName() + " ";
}
}
final String toastMessage =
"The following emotions were detected:\n\n"
+ detectedTones.toUpperCase();
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getBaseContext(),
toastMessage, Toast.LENGTH_LONG).show();
}
});
}
#Override
public void onFailure(Exception e) {
e.printStackTrace();
}
});
}
});
}
}
Can somebody point out what am i doing wrong. I have kept my credentials.json file in raw folder.
I tried writing every emotion in my Android App but i keep getting no response. Any help would be greatly appreciated.

Android Pusher Singleton channel subscription

Hello I have implemented pusher for realtime chat and subscribing to pusher channel , but I have many activities and fragments where i want to listen to pushr events . I have added this code in every activity/fragment but the problem is that it creates multiple subscriptions for every id . I know that i have to use Singleton for this can anyone point me in the right direction to achieve this ?
Here is the code i am writing in every activity/fragment
private PusherOptions options;
private Channel channel;
private Pusher pusher;
options = new PusherOptions();
options.setCluster("ap2");
pusher = new Pusher("afbfc1f591fd7b70190f", options);
pusher.connect();
profile_id = Global.shared().preferences.getString("PROFILE_ID", " ");
channel = pusher.subscribe(profile_id);
channel.bind("message",
new SubscriptionEventListener() {
#Override
public void onEvent(String s, String s1, final String data) {
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
JSONObject result = new JSONObject(data);
String message = result.getString("message");
String time = result.getString("time");
String reId = result.getString("recieverId");
new_message = message;
getConvoData(k, message);
} catch (JSONException e) {
e.printStackTrace();
}
System.out.println("DATA ====>>" + data);
}
});
}
});
okay so after trying for a while i figured it out my self i created a global class and just added pusher code to it so that it maintains just one connection for the entire lifecycle of the app
public class Global extends MultiDexApplication {
#Override
public void onCreate() {
super.onCreate();
SharedPreferences preferences = sharedInstance.getSharedPreferences(sharedInstance.getString(R.string.shared_preferences), Context.MODE_PRIVATE);
sharedInstance.preferences = preferences;
connectTopusher();
}
public void connectTopusher() {
PusherOptions options;
Channel channel;
Pusher pusher;
options = new PusherOptions();
options.setCluster("ap2");
pusher = new Pusher("afbfc1f591fd7b70190f", options);
pusher.connect();
String profile = Global.shared().preferences.getString("PROFILE_ID", "");
channel = pusher.subscribe(profile);
channel.bind("message",
new SubscriptionEventListener() {
#Override
public void onEvent(String s, String s1, final String data) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
try {
JSONObject result = new JSONObject(data);
String message = result.getString("message");
String time = result.getString("time");
String reId = result.getString("recieverId");
} catch (JSONException e) {
e.printStackTrace();
}
System.out.println("DATA ====>>" + data);
}
});
}
});
channel.bind("status_change", new SubscriptionEventListener() {
#Override
public void onEvent(String s, String s1, final String data) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
try {
JSONObject result = new JSONObject(data);
} catch (JSONException e) {
e.printStackTrace();
}
System.out.println("DATA ====>>" + data);
}
});
}
});
}
You can expose channel in your Global class. That will allow you to call bind and unbind in your fragments, when they are in the foreground.
connectToPusher should just create a channel and subscribe to it.
In Global.java:
private Channel channel;
public void connectTopusher() {
PusherOptions options;
Pusher pusher;
options = new PusherOptions();
options.setCluster("ap2");
pusher = new Pusher("afbfc1f591fd7b70190f", options);
pusher.connect();
String profile = Global.shared().preferences.getString("PROFILE_ID", "");
this.channel = pusher.subscribe(profile);
}
public Channel getChannel(){
return this.channel;
}
And then in your activity/fragment you can bind/unbind your listeners to when they are resumed/paused - just keep a reference to it like this:
YourActivity.java (could also be your Fragment)
private SubscriptionEventListener messageListener = new SubscriptionEventListener(){
#Override
public void onEvent(String channel, String event, String data) {
//TODO: do something with events
}
}
//Bind when the listener comes into the foreground:
#Override
protected void onResume() {
super.onResume();
((Global) getActivity().getApplication()).getChannel().bind("message", messageListener);
}
//Make sure to unbind the event listener!
#Override
protected void onPause() {
super.onPause();
((Global) getActivity().getApplication()).getChannel().unbind("message", messageListener);
}
I hope this helps :)

Chat works only one-way with Smack 4.1.7 Android

I am working on Android Chat app based on Smack 4.1.7.
I have created my XMPP related operations on Saperate class said MyXMPP.java.
and in my app's Application class i am initializing MyXMPP class objects.
my problem is, suppose we have user 1 and user 2. if user 1 sends message to user 2 then user 2 can get message but cant reply back. means if user 2 trying to reply then user 1 can not get user 2's reply.
in short if user 1 initiates chatting then, only user 1 can send message. user 2 can not send message to user 1 same Vice versa.
my codes are as below,
MyXMPP.java
public class MyXMPP {
static Context context;
static XMPPTCPConnectionConfiguration.Builder xmppConfig;
static XMPPTCPConnection connection;
static MyXMPP myXMPP = null;
static Chat chat;
Roster roster;
ArrayList<Rosters> rosters;
static ChatManager chatManager;
static Application app;
public static synchronized MyXMPP getInstance(Context c) {
app = (Application) c.getApplicationContext();
context = c;
if (myXMPP == null) {
myXMPP = new MyXMPP();
xmppConfig = XMPPTCPConnectionConfiguration.builder();
xmppConfig.setResource(Constants.RESOURCE);
xmppConfig.setServiceName(Constants.SERVICE_NAME);
xmppConfig.setPort(Constants.PORT);
xmppConfig.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
}
return myXMPP;
}
public static synchronized AbstractXMPPConnection getConnectXMPP() {
try {
xmppConfig.setUsernameAndPassword(Constants.USERNAME, Constants.PASSWORD);
XMPPTCPConnection.setUseStreamManagementDefault(true);
connection = new XMPPTCPConnection(xmppConfig.build());
connection.setUseStreamManagement(true);
connection.connect().login();
connection.requestSmAcknowledgement();
} catch (SmackException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (XMPPException e) {
e.printStackTrace();
}
return connection;
}
public static ChatManager getChatManager() {
if (chatManager == null) {
chatManager = ChatManager.getInstanceFor(app.connection);
}
return chatManager;
}
public ArrayList<Rosters> getRosters() {
rosters = new ArrayList<>();
roster = Roster.getInstanceFor(app.connection);
if (!roster.isLoaded())
try {
roster.reloadAndWait();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (SmackException.NotLoggedInException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
//Get Roster Entry list
Set<RosterEntry> rosterEntries = roster.getEntries();
Debug.e("entry size", "" + rosterEntries.size());
for (final RosterEntry entry : rosterEntries) {
/*
build List<> for roster entry with roster
---or---
if it is in activity or in fragment then add both items (entry,roster) to adapter
*/
Rosters rosterItem = new Rosters();
rosterItem.entry.add(entry);
rosterItem.roster.add(roster);
rosters.add(rosterItem);
}
return rosters;
}
public void initChatManager() {
if (chatManager == null) {
chatManager = getChatManager();
}
chatManager.addChatListener(new ChatManagerListener() {
#Override
public void chatCreated(Chat chat, boolean createdLocally) {
MyXMPP.chat = chat;
if (!createdLocally) {
chat.addMessageListener(new ChatMessageListener() {
#Override
public void processMessage(Chat chat, Message message) {
Debug.e("Chat obj", chat.toString());
if (message != null || !message.getBody().equalsIgnoreCase(null) || !message.getBody().equalsIgnoreCase("")) {
if (message.getBody() == null || message.getBody().equals(null)) {
} else {
Debug.e("Message aala", "" + message.getBody());
}
} else {
Debug.e("message null", "Message Null");
}
}
});
} else {
Debug.e("MY MSG", chat.getParticipant());
}
}
});
}
public void sendMessage(String to, String msg) {
Chat newChat = app.myXMPP.getChatManager().createChat(to, new ChatMessageListener() {
#Override
public void processMessage(Chat chat, Message message) {
System.out.println("Received message: " + message);
}
});
try {
Message message = new Message();
message.setFrom(connection.getUser());
message.setTo("xyz#myhostaddress.com");
message.setBody("My Message");
newChat.addMessageListener(new ChatMessageListener() {
#Override
public void processMessage(Chat chat, Message message) {
Debug.e("send msg listener", message.getBody());
}
});
newChat.sendMessage(message);
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
Application app;
Button btn;
String threadId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
app.myXMPP.sendMessage("xyz#myhost.com", "hello");
}
});
//Get Application data access
app = (Application) getApplicationContext();
//Establish Connection and Login
new XMPPOperations().execute();
}
class XMPPOperations extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
if (app.connection == null || !app.connection.isConnected()) {
app.connection = app.myXMPP.getConnectXMPP();
Debug.e("Connection in activity", "" + app.connection.isConnected());
}
app.myXMPP.getRosters();
app.myXMPP.initChatManager();
return null;
}
}
}
Application.java
public class Application extends android.app.Application {
public MyXMPP myXMPP;
public AbstractXMPPConnection connection;
#Override
public void onCreate() {
super.onCreate();
myXMPP = MyXMPP.getInstance(this);
}
#Override
public void onTerminate() {
super.onTerminate();
Presence p = new Presence(Presence.Type.unavailable);
try {
connection.sendStanza(p);
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
}
}

Servlet WebSocket Acessed by Android

I'm trying learn how to use the websocket and make a simple servlet for being connected with Android but I don't get it.
The index.jsp :
var ws = new WebSocket("ws://" + document.location.host + "/myws/ServletWS");
ws.onopen = function() { };
ws.onclose = function() { };
ws.onerror = function() { log("ERROR"); };
ws.onmessage = function(data) { var message = data.data; };
function sendMessage(msg) { ws.send(msg); }
How or where I receive the data from client?
Now on the servlet:
#Override protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) {
return new ConnectionWS();
}
class ConnectionWS extends MessageInbound {
private WsOutbound outbound;
#Override protected void onOpen(WsOutbound outbound) {
this.outbound = outbound;
}
#Override protected void onTextMessage(CharBuffer msg) throws IOException {
String message = msg.toString();
ServletWS.processData(message);
}
public void sendMessage(String message) {
CharBuffer cb = CharBuffer.wrap(message);
try {
outbound.writeTextMessage(cb);
} catch (IOException e) {}
}
}
public void processData(String message){
here I have to call the sendMessage with the answer to the client
}
I have saw a lot of examples on web but all of then about chat.
Thanks a lot for any help.
I understand that, you have a basic knowledge about tomcat configuration as well as java Servlet programming. As WekSocket is newly introduced in Tomcat, you may need to use latest tomcat version to implement WebSocket over it. I have used Apache Tomcat 7.0.42 for it.
So here we go. First, create a Servlet which will just create a new WebSocket for the request. You may need to modify it, if you want to go by session rather than request. Here is sample code.
import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WebSocketServlet;
public class WsChatServlet extends WebSocketServlet {
private static final long serialVersionUID = 1456546233L;
#Override
protected StreamInbound createWebSocketInbound(String protocol,
HttpServletRequest request) {
return new IncomingMessageHandler();
}
}
Now, create a Message Handler class which will handle each WebSocket stream independently. and that's it !
public class IncomingMessageHandler extends MessageInbound {
private WsOutbound myoutbound;
public IncomingMessageHandler() {
}
#Override
public void onOpen(WsOutbound outbound) {
logger.info("Open Client.");
this.myoutbound = outbound;
}
#Override
public void onClose(int status) {
logger.info("Close Client.");
}
/**
* Called when received plain Text Message
*/
#Override
public void onTextMessage(CharBuffer cb) throws IOException {
}
/**
* We can use this method to pass image binary data, eventually !
*/
#Override
public void onBinaryMessage(ByteBuffer bb) throws IOException {
}
public synchronized void sendTextMessage(String message) {
try {
CharBuffer buffer = CharBuffer.wrap(message);
this.getMyoutbound().writeTextMessage(buffer);
this.getMyoutbound().flush();
} catch (IOException e) {
}
}
/**
* Set websocket connection timeout in milliseconds,
* -1 means never
*/
#Override
public int getReadTimeout() {
return -1;
}
public WsOutbound getMyoutbound() {
return myoutbound;
}
public void setMyoutbound(WsOutbound myoutbound) {
this.myoutbound = myoutbound;
}
}
If not misunderstood and you want to use web sockets on Android then recommended API for you is jWebSocket.
Get it here, hopefully it already provides you APIs for a lot of the work that you need to do or even more.
http://jwebsocket.org/

Categories

Resources