package org.gsm.rcsApp.activities;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.gsm.rcsApp.ServiceURL;
import org.gsm.rcsApp.RCS.ChatMessage;
import org.gsm.rcsApp.RCS.ChatSessionManager;
import org.gsm.rcsApp.RCS.Contact;
import org.gsm.rcsApp.RCS.ContactState;
import org.gsm.rcsApp.RCS.ContactStateManager;
import org.gsm.rcsApp.adapters.ContactRowAdapter;
import org.gsm.rcsApp.misc.RCSJsonHttpResponseHandler;
import org.gsm.rcsApp.misc.Utils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import com.loopj.android.http.AsyncHttpClient;
import org.gsm.RCSDemo.R;
public class MainActivity extends Activity implements Runnable {
public final static String SELECTED_CONTACT = "com.mobilelife.rcsApp.activities.MainActivity.SELECTEDCONTACT";
public static ContactStateManager contactStateManager=new ContactStateManager();
private static ArrayList<Contact> retrievedContacts=new ArrayList<Contact>();
private static HashMap<String,Contact> contactMap=new HashMap<String,Contact>();
public static ChatSessionManager chatSessionCache=new ChatSessionManager();
static Thread background=null;
static boolean running=false;
private static HashMap<String, ArrayList<ChatMessage>> messageCache=new HashMap<String, ArrayList<ChatMessage>>();
static MainActivity _instance=null;
static ContactRowAdapter cradapter=null;
static ListView contactListView=null;
private static Handler changeStateHandler = null;
private static Handler contactChangeHandler = null;
static String currentChatSessionContactUri=null;
private static final int MAIN_LOOP_DELAY=5000;
private static final int LONGPOLL_TIMEOUT=30000;
private static Vibrator v = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
_instance=this;
v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
ContactStateManager.reset();
contactStateManager.clearCache();
contactListView=(ListView) findViewById(R.id.contactList);
cradapter=new ContactRowAdapter(this, retrievedContacts);
contactListView.setAdapter(cradapter);
contactListView.setFocusable(true);
contactListView.setOnItemClickListener(new ListView.OnItemClickListener() {
@SuppressWarnings("rawtypes")
public void onItemClick(AdapterView parent, View view, int position, long id) {
Contact selectedRecord=retrievedContacts.get(position);
currentChatSessionContactUri=selectedRecord.getContactId();
selectedRecord.setHasNewMessage(false);
ContactState contactState=contactStateManager.getOrCreateContactState(currentChatSessionContactUri);
ChatSessionActivity.setContactState(contactState);
contactState.setNewMessage(false);
contactStateManager.setChatVisible(currentChatSessionContactUri, true);
Intent intent = new Intent(_instance, ChatSessionActivity.class);
intent.putExtra(SELECTED_CONTACT, selectedRecord);
startActivity(intent);
}
});
contactListView.setOnItemLongClickListener(new ListView.OnItemLongClickListener() {
@SuppressWarnings("rawtypes")
public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {
Contact selectedRecord=retrievedContacts.get(position);
Intent intent = new Intent(_instance, EditContactActivity.class);
intent.putExtra(SELECTED_CONTACT, selectedRecord);
startActivity(intent);
return true;
}
});
contactChangeHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
refreshContacts();
}
};
changeStateHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
cradapter.notifyDataSetChanged();
contactListView.refreshDrawableState();
}
};
}
public void onStart() {
super.onStart();
if (currentChatSessionContactUri!=null) {
contactStateManager.setChatVisible(currentChatSessionContactUri, false);
}
if (!running) {
running=true;
background=new Thread(this);
background.start();
}
refreshContacts();
}
public static void stopMainActivity() {
running=false;
if (background!=null) {
running=false;
if (background!=null) {
background.interrupt();
background=null;
}
}
contactStateManager.clearCache();
ContactStateManager.reset();
}
public void refreshContacts() {
final String url=ServiceURL.getContactListURL(SplashActivity.userId);
if (SplashActivity.userId!=null) {
AsyncHttpClient client = new AsyncHttpClient();
AuthScope authscope=new AuthScope(ServiceURL.serverName, ServiceURL.serverPort, AuthScope.ANY_REALM);
client.setBasicAuth(SplashActivity.userId, SplashActivity.appCredentialPassword, authscope);
client.get(url, new RCSJsonHttpResponseHandler() {
@Override
public void onSuccess(JSONObject response, int errorCode) {
Log.d("MainActivity", "refreshContacts errorCode="+errorCode+" response="+(response!=null?response.toString():null));
if (response!=null) {
try {
if (errorCode==200) {
JSONObject contactCollection=Utils.getJSONObject(response, "contactCollection");
if (contactCollection!=null) {
JSONArray contactList=Utils.getJSONArray(contactCollection, "contact");
retrievedContacts.clear();
if (contactList!=null) {
for (int i=0; i<contactList.length(); i++) {
JSONObject contact=(JSONObject) contactList.get(i);
Log.d("MainActivity", "["+i+"] = "+contact.toString());
String contactId=Utils.getJSONStringElement(contact, "contactId");
String resourceURL=null;
String displayName=null;
String capabilities=null;
JSONObject attributeList=Utils.getJSONObject(contact, "attributeList");
if (attributeList!=null) {
resourceURL=Utils.getJSONStringElement(attributeList, "resourceURL");
JSONArray attributes=Utils.getJSONArray(attributeList, "attribute");
if (attributes!=null) {
for (int a=0; a<attributes.length();a++) {
JSONObject attribute=attributes.getJSONObject(a);
String name=Utils.getJSONStringElement(attribute, "name");
String value=Utils.getJSONStringElement(attribute, "value");
if (name!=null && name.equals("display-name")) {
displayName=value;
}
if (name!=null && name.equals("capabilities")) {
capabilities=value;
}
}
}
}
// String icon=contact.getString("icon");
// String status=contact.getString("status");
ContactState cs=contactStateManager.getOrCreateContactState(contactId);
Contact contactRecord=new Contact();
contactRecord.setContactId(contactId);
contactRecord.setResourceURL(resourceURL);
contactRecord.setDisplayName(displayName);
contactRecord.setCapabilities(capabilities);
// contactRecord.setIcon(icon);
// contactRecord.setStatus(status);
contactRecord.setHasNewMessage(cs.isNewMessage());
retrievedContacts.add(contactRecord);
contactMap.put(contactId, contactRecord);
}
changeStateHandler.sendEmptyMessage(0);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
public void onFailure(Throwable e, String response) {
Log.d("MainActivity", "No response from "+url);
}
});
}
}
public void run() {
Log.d("MainActivity", "Main background thread started");
long lastRequestTime=0;
while (running) {
boolean makeRequest=false;
long now=System.currentTimeMillis();
makeRequest=(now-lastRequestTime)>=MAIN_LOOP_DELAY; // Throttle so that do not drive through too many requests
final String notificationsUrl=SplashActivity.notificationChannelURL!=null?(SplashActivity.notificationChannelURL.replaceAll("tel\\:\\+", "tel%3A%2B").replaceAll("tel\\:", "tel%3A")):null;
if (notificationsUrl!=null && makeRequest ) {
DefaultHttpClient client = new DefaultHttpClient();
HttpParams myParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(myParams, MAIN_LOOP_DELAY);
HttpConnectionParams.setSoTimeout(myParams, LONGPOLL_TIMEOUT);
HttpPost httppost = new HttpPost(notificationsUrl);
lastRequestTime=now;
HttpResponse response=null;
try {
response = client.execute(httppost);
} catch (java.net.SocketTimeoutException ste) {
Log.d("MainActivity", "SocketTimeout handled");
} catch (ClientProtocolException e) {
Log.d("MainActivity", "ClientProtocolException handled");
} catch (IOException e) {
Log.d("MainActivity", "IOException handled");
}
int statusCode=response!=null&&response.getStatusLine()!=null?response.getStatusLine().getStatusCode():-1;
JSONObject jsonData=null;
try {
jsonData = getJSONDataFromResponse(response);
} catch (IllegalStateException e) {
Log.d("MainActivity", "IllegalStateException handled");
} catch (IOException e) {
Log.d("MainActivity", "IOException handled");
} catch (JSONException e) {
Log.d("MainActivity", "JSONException handled");
}
if (jsonData!=null) {
try {
processNotificationResponse(statusCode, jsonData);
} catch (JSONException e) {
Log.d("MainActivity", "JSONException handled");
}
}
} else {
try {
Thread.yield();
Thread.sleep (1000); // milliseconds
} catch (InterruptedException ie) {}
}
}
}
private void processNotificationResponse(int statusCode, JSONObject response) throws JSONException {
JSONArray notifications=response!=null?response.getJSONArray("notificationList"):null;
if (notifications!=null && notifications.length()>0) {
for (int i=0; i<notifications.length(); i++) {
JSONObject notification=notifications.getJSONObject(i);
Log.d("MainActivity", "Notification ["+i+"] = "+notification.toString());
if (Utils.getJSONObject(notification, "messageNotification")!=null) {
JSONObject messageNotification=Utils.getJSONObject(notification, "messageNotification");
if (Utils.getJSONObject(messageNotification, "isComposing")!=null) {
JSONObject isComposing=Utils.getJSONObject(messageNotification, "isComposing");
String senderAddress=Utils.getJSONStringElement(messageNotification, "senderAddress");
String status=Utils.getJSONStringElement(isComposing, "status");
if (senderAddress!=null) {
if (senderAddress.equals(currentChatSessionContactUri)) {
ChatSessionActivity.updateComposingIndicator(status);
}
contactStateManager.updateComposingIndicator(senderAddress, status);
}
}
if (Utils.getJSONObject(messageNotification, "chatMessage")!=null) {
JSONObject chatMessage=Utils.getJSONObject(messageNotification, "chatMessage");
String senderAddress=Utils.getJSONStringElement(messageNotification, "senderAddress");
String messageId=Utils.getJSONStringElement(messageNotification, "messageId");
String sessionId=Utils.getJSONStringElement(messageNotification, "sessionId");
String messageText=Utils.getJSONStringElement(chatMessage, "text");
String dateTime=Utils.getJSONStringElement(messageNotification, "dateTime");
ArrayList<ChatMessage> messageBuffer=messageCache.get(senderAddress);
if (messageBuffer==null) {
messageBuffer=new ArrayList<ChatMessage>();
messageCache.put(senderAddress, messageBuffer);
}
ChatMessage received=new ChatMessage();
received.setMessageText(messageText);
received.setMessageDirection(ChatMessage.MESSAGE_RECEIVED);
received.setMessageTime(Utils.convertTransferDateToDisplayString(dateTime));
received.setStatus(ChatMessage.MESSAGE_STATUS_RECEIVED);
String url=ServiceURL.getSendMessageStatusReportURL(SplashActivity.userId, senderAddress, sessionId, messageId);
String jsonData=null;
if (senderAddress!=null) {
if (senderAddress.equals(currentChatSessionContactUri)) {
jsonData="{\"messageStatusReport\":{\"status\":\"Displayed\"}}";
ChatSessionActivity.refreshMessageList(senderAddress, SplashActivity.userId, received);
} else {
jsonData="{\"messageStatusReport\":{\"status\":\"Delivered\"}}";
contactStateManager.storeMessage(senderAddress, received, true, SplashActivity.userId);
Contact found=contactMap.get(senderAddress);
if (found!=null && !found.isHasNewMessage()) {
found.setHasNewMessage(true);
changeStateHandler.sendEmptyMessage(0);
}
}
}
AsyncHttpClient responseClient = new AsyncHttpClient();
AuthScope authscope=new AuthScope(ServiceURL.serverName, ServiceURL.serverPort, AuthScope.ANY_REALM);
responseClient.setBasicAuth(SplashActivity.userId, SplashActivity.appCredentialPassword, authscope);
final String responseURL=url;
Log.d("MainActivity", "Sending message status update "+responseURL+" with "+jsonData);
StringEntity requestData;
try {
requestData = new StringEntity(jsonData);
responseClient.put(_instance.getApplication().getApplicationContext(),
url, requestData, "application/json", new RCSJsonHttpResponseHandler() {
@Override
public void onSuccess(JSONObject response, int errorCode) {
Log.d("MainActivity", "messageStatusReport::success = "+response.toString()+" errorCode="+errorCode);
}
@Override
public void onFailure(Throwable e, JSONObject response, int errorCode) {
Log.d("MainActivity", "messageStatusReport::failure = "+response.toString()+" errorCode="+errorCode);
}
});
} catch (UnsupportedEncodingException e) {}
v.vibrate(200);
}
} else if (Utils.getJSONObject(notification, "chatSessionInvitationNotification")!=null) {
JSONObject chatSessionInvitationNotification=Utils.getJSONObject(notification, "chatSessionInvitationNotification");
JSONArray link=Utils.getJSONArray(chatSessionInvitationNotification, "link");
if (link!=null && link.length()>0) {
for (int li=0; li<link.length(); li++) {
JSONObject litem=link.getJSONObject(li);
String rel=Utils.getJSONStringElement(litem, "rel");
String href=Utils.getJSONStringElement(litem, "href");
if ("ParticipantSessionStatus".equals(rel) && href!=null) {
AsyncHttpClient acceptClient = new AsyncHttpClient();
AuthScope authscope=new AuthScope(ServiceURL.serverName, ServiceURL.serverPort, AuthScope.ANY_REALM);
acceptClient.setBasicAuth(SplashActivity.userId, SplashActivity.appCredentialPassword, authscope);
try {
StringEntity requestData = new StringEntity("{\"participantSessionStatus\":{\"status\":\"Connected\"}}");
acceptClient.put(_instance.getApplication().getApplicationContext(),
href, requestData, "application/json", new RCSJsonHttpResponseHandler() {
@Override
public void onSuccess(String response, int errorCode) {
Log.d("MainActivity", "accept chatSessionInvitationNotification::success = "+response+" errorCode="+errorCode);
}
@Override
public void onFailure(Throwable e, JSONObject response, int errorCode) {
Log.d("MainActivity", "accept chatSessionInvitationNotification::failure = "+response.toString()+" errorCode="+errorCode);
}
});
} catch (UnsupportedEncodingException e) {}
}
}
}
} else if (Utils.getJSONObject(notification, "sessionEventNotification")!=null) {
JSONObject sessionEventNotification=Utils.getJSONObject(notification, "sessionEventNotification");
String event=Utils.getJSONStringElement(sessionEventNotification, "event");
if ("unregisterSuccess".equalsIgnoreCase(event)) {
contactChangeHandler.sendEmptyMessage(0);
}
} else if (Utils.getJSONObject(notification, "contactEventNotification")!=null) {
contactChangeHandler.sendEmptyMessage(0);
} else if (Utils.getJSONObject(notification, "messageStatusNotification")!=null) {
JSONObject messageStatusNotification=Utils.getJSONObject(notification, "messageStatusNotification");
String messageId=Utils.getJSONStringElement(messageStatusNotification, "messageId");
String status=Utils.getJSONStringElement(messageStatusNotification, "status");
ChatMessage message=ContactStateManager.getMessageForId(messageId);
Log.d("MainActivity", "updating status messageId="+messageId+" status="+status+" message="+message);
if (status!=null && message!=null) {
String contactUri=message.getContactUri();
if (status.equalsIgnoreCase("delivered")) {
if (contactUri!=null && contactUri.equals(currentChatSessionContactUri)) {
ChatSessionActivity.updateStatus(messageId,ChatMessage.MESSAGE_STATUS_DELIVERED);
} else {
ContactStateManager.updateStatusFor(messageId,ChatMessage.MESSAGE_STATUS_DELIVERED);
}
} else if (status.equalsIgnoreCase("displayed")) {
if (contactUri!=null && contactUri.equals(currentChatSessionContactUri)) {
ChatSessionActivity.updateStatus(messageId,ChatMessage.MESSAGE_STATUS_VIEWED);
} else {
ContactStateManager.updateStatusFor(messageId,ChatMessage.MESSAGE_STATUS_VIEWED);
}
}
}
} else if (Utils.getJSONObject(notification, "chatEventNotification")!=null) {
JSONObject chatEventNotification=Utils.getJSONObject(notification, "chatEventNotification");
String eventType=Utils.getJSONStringElement(chatEventNotification, "eventType");
if (eventType!=null && eventType.equalsIgnoreCase("SessionEnded")) {
contactChangeHandler.sendEmptyMessage(0);
}
}
}
}
}
private JSONObject getJSONDataFromResponse(HttpResponse response) throws IllegalStateException, IOException, JSONException {
JSONObject jsonData=null;
HttpEntity entity = response!=null&&response.getEntity()!=null?response.getEntity():null;
if (entity != null) {
InputStream instream = entity.getContent();
final StringBuilder out = new StringBuilder();
int bufferSize=1024;
final char[] buffer = new char[bufferSize];
int nread;
InputStreamReader reader = new InputStreamReader(instream);
while ((nread=reader.read(buffer, 0, buffer.length))>=0) {
out.append(buffer, 0, nread);
}
if (out.length()>0) jsonData = new JSONObject(out.toString());
}
return jsonData;
}
public void addContactClicked(View view) {
Intent intent = new Intent(_instance, AddContactActivity.class);
startActivity(intent);
}
public static void chatSessionClosed(String destinationUri) {
if (destinationUri.equals(currentChatSessionContactUri)) {
currentChatSessionContactUri=null;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_screen_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.refreshContacts:
contactChangeHandler.sendEmptyMessage(0);
return true;
case R.id.signOut:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}