PageRenderTime 61ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/resources/ExDataset/codechanges/208/new/ChatController.java

https://bitbucket.org/tamnguyenthe/exassist_repo
Java | 2452 lines | 1770 code | 463 blank | 219 comment | 400 complexity | 250b376310c7c10c4081a08ab1ebdbb3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. package com.twofours.surespot.chat;
  2. import io.socket.IOAcknowledge;
  3. import io.socket.IOCallback;
  4. import io.socket.SocketIO;
  5. import io.socket.SocketIOException;
  6. import java.io.BufferedInputStream;
  7. import java.io.File;
  8. import java.io.FileInputStream;
  9. import java.io.FileNotFoundException;
  10. import java.io.IOException;
  11. import java.io.InputStream;
  12. import java.io.InterruptedIOException;
  13. import java.io.PipedInputStream;
  14. import java.io.PipedOutputStream;
  15. import java.net.URI;
  16. import java.net.URISyntaxException;
  17. import java.util.ArrayList;
  18. import java.util.Date;
  19. import java.util.HashMap;
  20. import java.util.Iterator;
  21. import java.util.List;
  22. import java.util.Map.Entry;
  23. import java.util.Timer;
  24. import java.util.TimerTask;
  25. import java.util.concurrent.ConcurrentLinkedQueue;
  26. import org.json.JSONArray;
  27. import org.json.JSONException;
  28. import org.json.JSONObject;
  29. import android.app.Activity;
  30. import android.app.NotificationManager;
  31. import android.content.BroadcastReceiver;
  32. import android.content.Context;
  33. import android.content.Intent;
  34. import android.content.IntentFilter;
  35. import android.graphics.Bitmap;
  36. import android.net.ConnectivityManager;
  37. import android.net.NetworkInfo;
  38. import android.os.AsyncTask;
  39. import android.support.v4.app.FragmentManager;
  40. import android.support.v4.view.ViewPager;
  41. import android.text.TextUtils;
  42. import ch.boye.httpclientandroidlib.Header;
  43. import ch.boye.httpclientandroidlib.HttpStatus;
  44. import ch.boye.httpclientandroidlib.HttpVersion;
  45. import ch.boye.httpclientandroidlib.StatusLine;
  46. import ch.boye.httpclientandroidlib.client.cache.HttpCacheEntry;
  47. import ch.boye.httpclientandroidlib.cookie.Cookie;
  48. import ch.boye.httpclientandroidlib.impl.client.cache.HeapResource;
  49. import ch.boye.httpclientandroidlib.impl.cookie.DateUtils;
  50. import ch.boye.httpclientandroidlib.message.BasicHeader;
  51. import ch.boye.httpclientandroidlib.message.BasicStatusLine;
  52. import com.actionbarsherlock.view.MenuItem;
  53. import com.loopj.android.http.AsyncHttpResponseHandler;
  54. import com.loopj.android.http.JsonHttpResponseHandler;
  55. import com.twofours.surespot.R;
  56. import com.twofours.surespot.StateController;
  57. import com.twofours.surespot.StateController.FriendState;
  58. import com.twofours.surespot.SurespotApplication;
  59. import com.twofours.surespot.activities.MainActivity;
  60. import com.twofours.surespot.common.SurespotConfiguration;
  61. import com.twofours.surespot.common.SurespotConstants;
  62. import com.twofours.surespot.common.SurespotLog;
  63. import com.twofours.surespot.common.Utils;
  64. import com.twofours.surespot.encryption.EncryptionController;
  65. import com.twofours.surespot.friends.AutoInviteData;
  66. import com.twofours.surespot.friends.Friend;
  67. import com.twofours.surespot.friends.FriendAdapter;
  68. import com.twofours.surespot.identity.IdentityController;
  69. import com.twofours.surespot.images.MessageImageDownloader;
  70. import com.twofours.surespot.network.IAsyncCallback;
  71. import com.twofours.surespot.network.IAsyncCallbackTuple;
  72. import com.twofours.surespot.network.NetworkController;
  73. import com.viewpagerindicator.TitlePageIndicator;
  74. public class ChatController {
  75. private static final String TAG = "ChatController";
  76. private static final int STATE_CONNECTING = 0;
  77. private static final int STATE_CONNECTED = 1;
  78. private static final int STATE_DISCONNECTED = 2;
  79. private static final int MAX_RETRIES = 16;
  80. private final StatusLine mImageStatusLine = new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "");
  81. private SocketIO socket;
  82. private int mRetries = 0;
  83. private Timer mBackgroundTimer;
  84. private IOCallback mSocketCallback;
  85. private ConcurrentLinkedQueue<SurespotMessage> mSendBuffer = new ConcurrentLinkedQueue<SurespotMessage>();
  86. private ConcurrentLinkedQueue<SurespotMessage> mResendBuffer = new ConcurrentLinkedQueue<SurespotMessage>();
  87. private int mConnectionState;
  88. private boolean mOnWifi;
  89. private NotificationManager mNotificationManager;
  90. private BroadcastReceiver mConnectivityReceiver;
  91. private HashMap<String, ChatAdapter> mChatAdapters;
  92. private HashMap<String, Integer> mEarliestMessage;
  93. private FriendAdapter mFriendAdapter;
  94. private ChatPagerAdapter mChatPagerAdapter;
  95. private ViewPager mViewPager;
  96. private TitlePageIndicator mIndicator;
  97. private FragmentManager mFragmentManager;
  98. private int mLatestUserControlId;
  99. private ArrayList<MenuItem> mMenuItems;
  100. private HashMap<String, LatestIdPair> mPreConnectIds;
  101. private static String mCurrentChat;
  102. private static boolean mPaused = true;
  103. private NetworkController mNetworkController;
  104. private Context mContext;
  105. public static final int MODE_NORMAL = 0;
  106. public static final int MODE_SELECT = 1;
  107. private int mMode = MODE_NORMAL;
  108. private IAsyncCallbackTuple<String, Boolean> mCallback401;
  109. private IAsyncCallback<Boolean> mProgressCallback;
  110. private IAsyncCallback<Void> mSendIntentCallback;
  111. private IAsyncCallback<Friend> mTabShowingCallback;
  112. private AutoInviteData mAutoInviteData;
  113. public ChatController(Context context, NetworkController networkController, FragmentManager fm, IAsyncCallbackTuple<String, Boolean> m401Handler,
  114. IAsyncCallback<Boolean> progressCallback, IAsyncCallback<Void> sendIntentCallback, IAsyncCallback<Friend> tabShowingCallback) {
  115. SurespotLog.v(TAG, "constructor: " + this);
  116. mContext = context;
  117. mNetworkController = networkController;
  118. mCallback401 = m401Handler;
  119. mProgressCallback = progressCallback;
  120. mSendIntentCallback = sendIntentCallback;
  121. mTabShowingCallback = tabShowingCallback;
  122. mEarliestMessage = new HashMap<String, Integer>();
  123. mChatAdapters = new HashMap<String, ChatAdapter>();
  124. mFriendAdapter = new FriendAdapter(mContext);
  125. mPreConnectIds = new HashMap<String, ChatController.LatestIdPair>();
  126. loadState();
  127. mFragmentManager = fm;
  128. mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
  129. setOnWifi();
  130. // mViewPager.setOffscreenPageLimit(2);
  131. mSocketCallback = new IOCallback() {
  132. @Override
  133. public void onMessage(JSONObject json, IOAcknowledge ack) {
  134. try {
  135. SurespotLog.v(TAG, "JSON Server said: %s", json.toString(2));
  136. }
  137. catch (JSONException e) {
  138. SurespotLog.w(TAG, "onMessage", e);
  139. }
  140. }
  141. @Override
  142. public void onMessage(String data, IOAcknowledge ack) {
  143. SurespotLog.v(TAG, "Server said: %s", data);
  144. }
  145. @Override
  146. public synchronized void onError(SocketIOException socketIOException) {
  147. // socket.io returns 403 for can't login
  148. if (socketIOException.getHttpStatus() == 403) {
  149. socket = null;
  150. logout();
  151. mCallback401.handleResponse(mContext.getString(R.string.could_not_login_to_server), false);
  152. return;
  153. }
  154. SurespotLog.i(TAG, socketIOException, "an Error occured, attempting reconnect with exponential backoff, retries: %d", mRetries);
  155. setOnWifi();
  156. // kick off another task
  157. if (mRetries < MAX_RETRIES) {
  158. if (mReconnectTask != null) {
  159. mReconnectTask.cancel();
  160. }
  161. int timerInterval = (int) (Math.pow(2, mRetries++) * 1000);
  162. SurespotLog.v(TAG, "Starting another task in: " + timerInterval);
  163. mReconnectTask = new ReconnectTask();
  164. if (mBackgroundTimer == null) {
  165. mBackgroundTimer = new Timer("backgroundTimer");
  166. }
  167. mBackgroundTimer.schedule(mReconnectTask, timerInterval);
  168. }
  169. else {
  170. // TODO tell user
  171. SurespotLog.i(TAG, "Socket.io reconnect retries exhausted, giving up.");
  172. mCallback401.handleResponse(mContext.getString(R.string.could_not_connect_to_server), true);
  173. }
  174. }
  175. @Override
  176. public void onDisconnect() {
  177. SurespotLog.v(TAG, "Connection terminated.");
  178. // socket = null;
  179. }
  180. @Override
  181. public void onConnect() {
  182. SurespotLog.v(TAG, "socket.io connection established");
  183. setState(STATE_CONNECTED);
  184. setOnWifi();
  185. mRetries = 0;
  186. if (mBackgroundTimer != null) {
  187. mBackgroundTimer.cancel();
  188. mBackgroundTimer = null;
  189. }
  190. if (mReconnectTask != null && mReconnectTask.cancel()) {
  191. SurespotLog.v(TAG, "Cancelled reconnect timer.");
  192. mReconnectTask = null;
  193. }
  194. connected();
  195. }
  196. @Override
  197. public void on(String event, IOAcknowledge ack, Object... args) {
  198. SurespotLog.v(TAG, "Server triggered event '" + event + "'");
  199. if (event.equals("control")) {
  200. try {
  201. SurespotControlMessage message = SurespotControlMessage.toSurespotControlMessage(new JSONObject((String) args[0]));
  202. handleControlMessage(null, message, true, false);
  203. }
  204. catch (JSONException e) {
  205. SurespotLog.w(TAG, "on control", e);
  206. }
  207. }
  208. else
  209. if (event.equals("message")) {
  210. try {
  211. JSONObject jsonMessage = new JSONObject((String) args[0]);
  212. SurespotLog.v(TAG, "received message: " + jsonMessage.toString());
  213. SurespotMessage message = SurespotMessage.toSurespotMessage(jsonMessage);
  214. handleMessage(message);
  215. checkAndSendNextMessage(message);
  216. // see if we have deletes
  217. String sDeleteControlMessages = jsonMessage.optString("deleteControlMessages", null);
  218. if (sDeleteControlMessages != null) {
  219. JSONArray deleteControlMessages = new JSONArray(sDeleteControlMessages);
  220. if (deleteControlMessages.length() > 0) {
  221. for (int i = 0; i < deleteControlMessages.length(); i++) {
  222. try {
  223. SurespotControlMessage dMessage = SurespotControlMessage.toSurespotControlMessage(new JSONObject(
  224. deleteControlMessages.getString(i)));
  225. handleControlMessage(null, dMessage, true, false);
  226. }
  227. catch (JSONException e) {
  228. SurespotLog.w(TAG, "on control", e);
  229. }
  230. }
  231. }
  232. }
  233. }
  234. catch (JSONException e) {
  235. SurespotLog.w(TAG, "on message", e);
  236. }
  237. }
  238. else
  239. if (event.equals("messageError")) {
  240. try {
  241. JSONObject jsonMessage = (JSONObject) args[0];
  242. SurespotLog.v(TAG, "received messageError: " + jsonMessage.toString());
  243. SurespotErrorMessage errorMessage = SurespotErrorMessage.toSurespotErrorMessage(jsonMessage);
  244. handleErrorMessage(errorMessage);
  245. }
  246. catch (JSONException e) {
  247. SurespotLog.w(TAG, "on messageError", e);
  248. }
  249. }
  250. }
  251. };
  252. mConnectivityReceiver = new BroadcastReceiver() {
  253. @Override
  254. public void onReceive(Context context, Intent intent) {
  255. SurespotLog.v(TAG, "Connectivity Action");
  256. ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
  257. NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
  258. if (networkInfo != null) {
  259. SurespotLog.v(TAG, "isconnected: " + networkInfo.isConnected());
  260. SurespotLog.v(TAG, "failover: " + networkInfo.isFailover());
  261. SurespotLog.v(TAG, "reason: " + networkInfo.getReason());
  262. SurespotLog.v(TAG, "type: " + networkInfo.getTypeName());
  263. // if it's not a failover and wifi is now active then initiate reconnect
  264. if (!networkInfo.isFailover() && (networkInfo.getType() == ConnectivityManager.TYPE_WIFI && networkInfo.isConnected())) {
  265. synchronized (ChatController.this) {
  266. // if we're not connecting, connect
  267. if (getState() != STATE_CONNECTING && !mOnWifi) {
  268. SurespotLog.v(TAG, "Network switch, Reconnecting...");
  269. setState(STATE_CONNECTING);
  270. mOnWifi = true;
  271. disconnect();
  272. connect();
  273. }
  274. }
  275. }
  276. }
  277. else {
  278. SurespotLog.v(TAG, "networkinfo null");
  279. }
  280. }
  281. };
  282. }
  283. // this has to be done outside of the contructor as it creates fragments, which need chat controller instance
  284. public void init(ViewPager viewPager, TitlePageIndicator pageIndicator, ArrayList<MenuItem> menuItems, AutoInviteData autoInviteData) {
  285. mChatPagerAdapter = new ChatPagerAdapter(mContext, mFragmentManager);
  286. mMenuItems = menuItems;
  287. mAutoInviteData = autoInviteData;
  288. mViewPager = viewPager;
  289. mViewPager.setAdapter(mChatPagerAdapter);
  290. mIndicator = pageIndicator;
  291. mIndicator.setViewPager(mViewPager);
  292. mIndicator.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
  293. @Override
  294. public void onPageSelected(int position) {
  295. if (mChatPagerAdapter != null) {
  296. SurespotLog.v(TAG, "onPageSelected, position: " + position);
  297. String name = mChatPagerAdapter.getChatName(position);
  298. setCurrentChat(name);
  299. }
  300. }
  301. });
  302. mChatPagerAdapter.setChatNames(mFriendAdapter.getActiveChats());
  303. onResume();
  304. }
  305. private void connect() {
  306. SurespotLog.v(TAG, "connect, socket: " + socket + ", connected: " + (socket != null ? socket.isConnected() : false) + ", state: " + mConnectionState);
  307. // copy the latest ids so that we don't miss any if we receive new messages during the time we request messages and when the
  308. // connection completes (if they
  309. // are received out of order for some reason)
  310. //
  311. mPreConnectIds.clear();
  312. for (Entry<String, ChatAdapter> entry : mChatAdapters.entrySet()) {
  313. String username = entry.getKey();
  314. LatestIdPair idPair = new LatestIdPair();
  315. idPair.latestMessageId = getLatestMessageId(username);
  316. idPair.latestControlMessageId = getLatestMessageControlId(username);
  317. SurespotLog.v(TAG, "setting preconnectids for: " + username + ", latest message id: " + idPair.latestMessageId + ", latestcontrolid: "
  318. + idPair.latestControlMessageId);
  319. mPreConnectIds.put(username, idPair);
  320. }
  321. Cookie cookie = IdentityController.getCookie();
  322. if (cookie == null) {
  323. return;
  324. }
  325. try {
  326. HashMap<String, String> headers = new HashMap<String, String>();
  327. headers.put("cookie", cookie.getName() + "=" + cookie.getValue());
  328. socket = new SocketIO(SurespotConfiguration.getBaseUrl(), headers);
  329. socket.connect(mSocketCallback);
  330. }
  331. catch (Exception e) {
  332. SurespotLog.w(TAG, "connect", e);
  333. }
  334. }
  335. private void disconnect() {
  336. SurespotLog.v(TAG, "disconnect.");
  337. setState(STATE_DISCONNECTED);
  338. if (socket != null) {
  339. socket.disconnect();
  340. socket = null;
  341. }
  342. }
  343. private void connected() {
  344. getFriendsAndIds();
  345. resendMessages();
  346. // if we need to invite someone then do it
  347. if (mAutoInviteData != null) {
  348. if (mFriendAdapter.getFriend(mAutoInviteData.getUsername()) == null) {
  349. mNetworkController.invite(mAutoInviteData.getUsername(), mAutoInviteData.getSource(), new AsyncHttpResponseHandler() {
  350. @Override
  351. public void onSuccess(int statusCode, String arg0) {
  352. getFriendAdapter().addFriendInvited(mAutoInviteData.getUsername());
  353. mAutoInviteData = null;
  354. }
  355. });
  356. }
  357. else {
  358. Utils.makeToast(mContext, mContext.getString(R.string.autoinvite_user_exists, mAutoInviteData.getUsername()));
  359. mAutoInviteData = null;
  360. }
  361. }
  362. }
  363. private void resendMessages() {
  364. // get the resend messages
  365. SurespotMessage[] resendMessages = getResendMessages();
  366. JSONArray sMessageList = new JSONArray();
  367. for (int i = 0; i < resendMessages.length; i++) {
  368. SurespotMessage message = resendMessages[i];
  369. // if it has an id don't send it again
  370. if (message.getId() != null) {
  371. mResendBuffer.remove(message);
  372. continue;
  373. }
  374. // set the last received id so the server knows which messages to check
  375. String otherUser = message.getOtherUser();
  376. // String username = message.getFrom();
  377. Integer lastMessageID = 0;
  378. // ideally get the last id from the fragment's chat adapter
  379. ChatAdapter chatAdapter = mChatAdapters.get(otherUser);
  380. if (chatAdapter != null) {
  381. SurespotMessage lastMessage = chatAdapter.getLastMessageWithId();
  382. if (lastMessage != null) {
  383. lastMessageID = lastMessage.getId();
  384. }
  385. }
  386. // failing that use the last viewed id
  387. if (lastMessageID == null) {
  388. mFriendAdapter.getFriend(otherUser).getLastViewedMessageId();
  389. }
  390. SurespotLog.v(TAG, "setting resendId, otheruser: " + otherUser + ", id: " + lastMessageID);
  391. message.setResendId(lastMessageID);
  392. // String sMessage = message.toJSONObject().toString();
  393. sMessageList.put(message.toJSONObject());
  394. // enqueueMessage(message);
  395. // sendMessages();
  396. }
  397. socket.send(sMessageList.toString());
  398. }
  399. private void setOnWifi() {
  400. // get the initial state...sometimes when the app starts it says "hey i'm on wifi" which creates a reconnect
  401. ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
  402. NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
  403. if (networkInfo != null) {
  404. mOnWifi = (networkInfo.getType() == ConnectivityManager.TYPE_WIFI);
  405. }
  406. }
  407. private void checkAndSendNextMessage(SurespotMessage message) {
  408. sendMessages();
  409. if (mResendBuffer.size() > 0) {
  410. if (mResendBuffer.remove(message)) {
  411. SurespotLog.v(TAG, "Received and removed message from resend buffer: " + message);
  412. }
  413. }
  414. }
  415. private SurespotMessage[] getResendMessages() {
  416. SurespotMessage[] messages = mResendBuffer.toArray(new SurespotMessage[0]);
  417. // mResendBuffer.clear();
  418. return messages;
  419. }
  420. private void enqueueMessage(SurespotMessage message) {
  421. mSendBuffer.add(message);
  422. }
  423. private synchronized void sendMessages() {
  424. if (mBackgroundTimer == null) {
  425. mBackgroundTimer = new Timer("backgroundTimer");
  426. }
  427. SurespotLog.v(TAG, "Sending: " + mSendBuffer.size() + " messages.");
  428. Iterator<SurespotMessage> iterator = mSendBuffer.iterator();
  429. while (iterator.hasNext()) {
  430. SurespotMessage message = iterator.next();
  431. if (isMessageReadyToSend(message)) {
  432. iterator.remove();
  433. sendMessage(message);
  434. }
  435. else {
  436. break;
  437. }
  438. }
  439. }
  440. private boolean isMessageReadyToSend(SurespotMessage message) {
  441. return !TextUtils.isEmpty(message.getData()) && !TextUtils.isEmpty(message.getFromVersion()) && !TextUtils.isEmpty(message.getToVersion());
  442. }
  443. private void sendMessage(final SurespotMessage message) {
  444. SurespotLog.v(TAG, "sendmessage adding message to ResendBuffer, text: %s, iv: %s", message.getPlainData(), message.getIv());
  445. mResendBuffer.add(message);
  446. if (getState() == STATE_CONNECTED) {
  447. SurespotLog.v(TAG, "sendmessage, socket: %s", socket);
  448. JSONObject json = message.toJSONObject();
  449. SurespotLog.v(TAG, "sendmessage, json: %s", json);
  450. String s = json.toString();
  451. SurespotLog.v(TAG, "sendmessage, message string: %s", s);
  452. if (socket != null) {
  453. socket.send(s);
  454. }
  455. }
  456. }
  457. private int getState() {
  458. return mConnectionState;
  459. }
  460. private synchronized void setState(int state) {
  461. mConnectionState = state;
  462. }
  463. private ReconnectTask mReconnectTask;
  464. private class ReconnectTask extends TimerTask {
  465. @Override
  466. public void run() {
  467. SurespotLog.v(TAG, "Reconnect task run.");
  468. connect();
  469. }
  470. }
  471. private void handleMessage(final SurespotMessage message) {
  472. SurespotLog.v(TAG, "handleMessage %s", message);
  473. final String otherUser = message.getOtherUser();
  474. final ChatAdapter chatAdapter = mChatAdapters.get(otherUser);
  475. // if the adapter is open add the message
  476. if (chatAdapter != null) {
  477. // decrypt the message before adding it so the size is set properly
  478. new AsyncTask<Void, Void, Void>() {
  479. @Override
  480. protected Void doInBackground(Void... params) {
  481. if (message.getMimeType().equals(SurespotConstants.MimeTypes.TEXT)) {
  482. // decrypt it before adding
  483. final String plainText = EncryptionController.symmetricDecrypt(message.getOurVersion(), message.getOtherUser(),
  484. message.getTheirVersion(), message.getIv(), message.getData());
  485. // substitute emoji
  486. if (plainText != null) {
  487. EmojiParser parser = EmojiParser.getInstance();
  488. message.setPlainData(parser.addEmojiSpans(plainText));
  489. }
  490. }
  491. else {
  492. if (message.getMimeType().equals(SurespotConstants.MimeTypes.IMAGE)) {
  493. // if it's an image that i sent
  494. // get the local message
  495. if (ChatUtils.isMyMessage(message)) {
  496. handleCachedFile(chatAdapter, message);
  497. }
  498. else {
  499. InputStream imageStream = MainActivity.getNetworkController().getFileStream(MainActivity.getContext(), message.getData());
  500. Bitmap bitmap = null;
  501. PipedOutputStream out = new PipedOutputStream();
  502. PipedInputStream inputStream;
  503. try {
  504. inputStream = new PipedInputStream(out);
  505. EncryptionController.runDecryptTask(message.getOurVersion(), message.getOtherUser(), message.getTheirVersion(),
  506. message.getIv(), new BufferedInputStream(imageStream), out);
  507. byte[] bytes = Utils.inputStreamToBytes(inputStream);
  508. bitmap = ChatUtils.getSampledImage(bytes);
  509. }
  510. catch (InterruptedIOException ioe) {
  511. SurespotLog.w(TAG, ioe, "handleMessage");
  512. }
  513. catch (IOException e) {
  514. SurespotLog.w(TAG, e, "handleMessage");
  515. }
  516. if (bitmap != null) {
  517. MessageImageDownloader.addBitmapToCache(message.getData(), bitmap);
  518. }
  519. }
  520. }
  521. else {
  522. if (message.getMimeType().equals(SurespotConstants.MimeTypes.M4A)) {
  523. if (ChatUtils.isMyMessage(message)) {
  524. handleCachedFile(chatAdapter, message);
  525. }
  526. else {
  527. InputStream encryptedVoiceStream = MainActivity.getNetworkController().getFileStream(MainActivity.getContext(),
  528. message.getData());
  529. PipedOutputStream out = new PipedOutputStream();
  530. PipedInputStream inputStream;
  531. try {
  532. inputStream = new PipedInputStream(out);
  533. EncryptionController.runDecryptTask(message.getOurVersion(), message.getOtherUser(), message.getTheirVersion(),
  534. message.getIv(), new BufferedInputStream(encryptedVoiceStream), out);
  535. byte[] bytes = Utils.inputStreamToBytes(inputStream);
  536. message.setPlainBinaryData(bytes);
  537. }
  538. catch (InterruptedIOException ioe) {
  539. SurespotLog.w(TAG, ioe, "handleMessage");
  540. }
  541. catch (IOException e) {
  542. SurespotLog.w(TAG, e, "handleMessage");
  543. }
  544. }
  545. }
  546. else {
  547. message.setPlainData("unknown message mime type");
  548. }
  549. }
  550. }
  551. return null;
  552. }
  553. protected void onPostExecute(Void result) {
  554. try {
  555. boolean added = applyControlMessages(chatAdapter, message, false, false, true);
  556. scrollToEnd(otherUser);
  557. Friend friend = mFriendAdapter.getFriend(otherUser);
  558. if (friend != null) {
  559. int messageId = message.getId();
  560. // always update the available id
  561. friend.setAvailableMessageId(messageId);
  562. // if the chat is showing set the last viewed id the id of the message we just received
  563. if (otherUser.equals(mCurrentChat)) {
  564. friend.setLastViewedMessageId(messageId);
  565. // if it was a voice message from the other user set play flag
  566. // TODO wrap in preference
  567. if (!ChatUtils.isMyMessage(message) && message.getMimeType().equals(SurespotConstants.MimeTypes.M4A)) {
  568. message.setPlayMedia(true);
  569. }
  570. }
  571. // chat not showing
  572. else {
  573. // if it's my message increment the count by one to account for it as I may have unread messages from the
  574. // other user; we
  575. // can't just set the last viewed to the latest message
  576. if (ChatUtils.isMyMessage(message) && added) {
  577. int adjustedLastViewedId = friend.getLastViewedMessageId() + 1;
  578. if (adjustedLastViewedId < messageId) {
  579. friend.setLastViewedMessageId(adjustedLastViewedId);
  580. }
  581. else {
  582. friend.setLastViewedMessageId(messageId);
  583. }
  584. }
  585. }
  586. mFriendAdapter.sort();
  587. mFriendAdapter.notifyDataSetChanged();
  588. }
  589. }
  590. catch (SurespotMessageSequenceException e) {
  591. SurespotLog.v(TAG, "handleMessage: %s", e.getMessage());
  592. getLatestMessagesAndControls(otherUser, e.getMessageId());
  593. }
  594. };
  595. }.execute();
  596. }
  597. else {
  598. Friend friend = mFriendAdapter.getFriend(otherUser);
  599. if (friend != null) {
  600. int messageId = message.getId();
  601. // always update the available id
  602. friend.setAvailableMessageId(messageId);
  603. mFriendAdapter.sort();
  604. mFriendAdapter.notifyDataSetChanged();
  605. }
  606. }
  607. }
  608. private boolean applyControlMessages(ChatAdapter chatAdapter, SurespotMessage message, boolean checkSequence, boolean sort, boolean notify)
  609. throws SurespotMessageSequenceException {
  610. // see if we have applicable control messages and apply them if necessary
  611. ArrayList<SurespotControlMessage> controlMessages = chatAdapter.getControlMessages();
  612. ArrayList<SurespotControlMessage> applicableControlMessages = new ArrayList<SurespotControlMessage>();
  613. for (SurespotControlMessage controlMessage : controlMessages) {
  614. int messageId = Integer.parseInt(controlMessage.getMoreData());
  615. if (message.getId() == messageId) {
  616. applicableControlMessages.add(controlMessage);
  617. }
  618. }
  619. boolean added = false;
  620. if (applicableControlMessages.size() == 0) {
  621. added = chatAdapter.addOrUpdateMessage(message, checkSequence, sort, notify);
  622. }
  623. else {
  624. added = chatAdapter.addOrUpdateMessage(message, checkSequence, false, false);
  625. for (SurespotControlMessage controlMessage : applicableControlMessages) {
  626. SurespotLog.v(TAG, "applying control message %s: to message %s", controlMessage, message);
  627. handleControlMessage(chatAdapter, controlMessage, false, true);
  628. }
  629. if (notify) {
  630. chatAdapter.notifyDataSetChanged();
  631. }
  632. }
  633. return added;
  634. }
  635. // add entry to http cache for image we sent so we don't download it again
  636. private void handleCachedFile(ChatAdapter chatAdapter, SurespotMessage message) {
  637. SurespotLog.v(TAG, "handleCachedFile");
  638. SurespotMessage localMessage = chatAdapter.getMessageByIv(message.getIv());
  639. // if the data is different we haven't updated the url to point externally
  640. if (localMessage != null && localMessage.getId() == null && !localMessage.getData().equals(message.getData())) {
  641. // add the remote cache entry for the new url
  642. String localUri = localMessage.getData();
  643. String remoteUri = message.getData();
  644. FileInputStream fis;
  645. try {
  646. fis = new FileInputStream(new File(new URI(localUri)));
  647. byte[] imageData = Utils.inputStreamToBytes(fis);
  648. HeapResource resource = new HeapResource(imageData);
  649. Date date = new Date();
  650. String sDate = DateUtils.formatDate(date);
  651. Header[] cacheHeaders = new Header[3];
  652. // create fake cache entry
  653. cacheHeaders[0] = new BasicHeader("Last-Modified", sDate);
  654. cacheHeaders[1] = new BasicHeader("Cache-Control", "public, max-age=31557600");
  655. cacheHeaders[2] = new BasicHeader("Date", sDate);
  656. HttpCacheEntry cacheEntry = new HttpCacheEntry(date, date, mImageStatusLine, cacheHeaders, resource);
  657. SurespotLog.v(TAG, "creating http cache entry for: %s", remoteUri);
  658. mNetworkController.addCacheEntry(remoteUri, cacheEntry);
  659. // update image cache
  660. if (message.getMimeType().equals(SurespotConstants.MimeTypes.IMAGE)) {
  661. MessageImageDownloader.copyAndRemoveCacheEntry(localUri, remoteUri);
  662. }
  663. }
  664. catch (FileNotFoundException e1) {
  665. SurespotLog.w(TAG, e1, "onMessage");
  666. }
  667. catch (URISyntaxException e1) {
  668. SurespotLog.w(TAG, e1, "onMessage");
  669. }
  670. catch (IOException e) {
  671. SurespotLog.w(TAG, e, "onMessage");
  672. }
  673. // delete the file
  674. try {
  675. SurespotLog.v(TAG, "handleCachedImage deleting local file: %s", localUri);
  676. File file = new File(new URI(localUri));
  677. file.delete();
  678. }
  679. catch (URISyntaxException e) {
  680. SurespotLog.w(TAG, e, "handleMessage");
  681. }
  682. // update message to point to real location
  683. localMessage.setData(remoteUri);
  684. }
  685. }
  686. // private void handleLocalData(ChatAdapter chatAdapter, SurespotMessage message) {
  687. // SurespotLog.v(TAG, "handleLocalData");
  688. // SurespotMessage localMessage = chatAdapter.getMessageByIv(message.getIv());
  689. //
  690. // // if the data is different we haven't updated the http cache with data we sent
  691. // if (localMessage != null && localMessage.getId() == null && !localMessage.getData().equals(message.getData()) && localMessage.getInlineData() != null) {
  692. // // add the remote cache entry for the new url
  693. //
  694. // byte[] imageData = localMessage.getInlineData();
  695. //
  696. // String remoteUri = message.getData();
  697. // HeapResource resource = new HeapResource(imageData);
  698. // Date date = new Date();
  699. // String sDate = DateUtils.formatDate(date);
  700. //
  701. // Header[] cacheHeaders = new Header[3];
  702. //
  703. // // create fake cache entry
  704. // cacheHeaders[0] = new BasicHeader("Last-Modified", sDate);
  705. // cacheHeaders[1] = new BasicHeader("Cache-Control", "public, max-age=31557600");
  706. // cacheHeaders[2] = new BasicHeader("Date", sDate);
  707. //
  708. // HttpCacheEntry cacheEntry = new HttpCacheEntry(date, date, mImageStatusLine, cacheHeaders, resource);
  709. //
  710. // SurespotLog.v(TAG, "creating http cache entry for: %s", remoteUri);
  711. // mNetworkController.addCacheEntry(remoteUri, cacheEntry);
  712. //
  713. // // update message to point to real location
  714. // localMessage.setData(remoteUri);
  715. //
  716. // // clear out the inline data as we should still have the decrypted plain data
  717. // localMessage.setInlineData(null);
  718. //
  719. // }
  720. // }
  721. // message handling shiznit
  722. void loadEarlierMessages(final String username, final IAsyncCallback<Boolean> callback) {
  723. // mLoading = true;
  724. // get the list of messages
  725. Integer firstMessageId = mEarliestMessage.get(username);
  726. if (firstMessageId == null) {
  727. firstMessageId = getEarliestMessageId(username);
  728. mEarliestMessage.put(username, firstMessageId);
  729. }
  730. // else {
  731. // firstMessageId -= 60;
  732. // if (firstMessageId < 1) {
  733. // firstMessageId = 1;
  734. // }
  735. // }
  736. if (firstMessageId != null) {
  737. if (firstMessageId > 1) {
  738. SurespotLog.v(TAG, username + ": asking server for messages before messageId: " + firstMessageId);
  739. // final int fMessageId = firstMessageId;
  740. final ChatAdapter chatAdapter = mChatAdapters.get(username);
  741. mNetworkController.getEarlierMessages(username, firstMessageId, new JsonHttpResponseHandler() {
  742. @Override
  743. public void onSuccess(final JSONArray jsonArray) {
  744. // if (getActivity() != null) {
  745. SurespotMessage message = null;
  746. try {
  747. for (int i = jsonArray.length() - 1; i >= 0; i--) {
  748. JSONObject jsonMessage = new JSONObject(jsonArray.getString(i));
  749. message = SurespotMessage.toSurespotMessage(jsonMessage);
  750. chatAdapter.insertMessage(message, false);
  751. }
  752. }
  753. catch (JSONException e) {
  754. SurespotLog.e(TAG, e, "%s: error creating chat message", username);
  755. }
  756. SurespotLog.v(TAG, "%s: loaded: %d earlier messages from the server.", username, jsonArray.length());
  757. if (message != null) {
  758. mEarliestMessage.put(username, message.getId());
  759. // chatAdapter.notifyDataSetChanged();
  760. }
  761. // chatAdapter.setLoading(false);
  762. callback.handleResponse(jsonArray.length() > 0);
  763. }
  764. @Override
  765. public void onFailure(Throwable error, String content) {
  766. SurespotLog.i(TAG, error, "%s: getEarlierMessages", username);
  767. // chatAdapter.setLoading(false);
  768. callback.handleResponse(false);
  769. }
  770. });
  771. }
  772. else {
  773. SurespotLog.v(TAG, "%s: getEarlierMessages: no more messages.", username);
  774. callback.handleResponse(false);
  775. // ChatFragment.this.mNoEarlierMessages = true;
  776. }
  777. }
  778. }
  779. private void getLatestIds() {
  780. SurespotLog.v(TAG, "getLatestIds");
  781. // setMessagesLoading(true);
  782. mNetworkController.getLatestIds(mLatestUserControlId, new JsonHttpResponseHandler() {
  783. @Override
  784. public void onSuccess(int statusCode, final JSONObject jsonResponse) {
  785. SurespotLog.v(TAG, "getlatestIds success, response: %s, statusCode: %d", jsonResponse, statusCode);
  786. JSONArray conversationIds = jsonResponse.optJSONArray("conversationIds");
  787. Friend friend = null;
  788. if (conversationIds != null) {
  789. for (int i = 0; i < conversationIds.length(); i++) {
  790. try {
  791. JSONObject jsonObject = conversationIds.getJSONObject(i);
  792. String spot = jsonObject.getString("conversation");
  793. Integer availableId = jsonObject.getInt("id");
  794. String user = ChatUtils.getOtherSpotUser(spot, IdentityController.getLoggedInUser());
  795. // update available ids
  796. friend = mFriendAdapter.getFriend(user);
  797. if (friend != null) {
  798. friend.setAvailableMessageId(availableId);
  799. }
  800. }
  801. catch (JSONException e) {
  802. SurespotLog.w(TAG, "getlatestIds", e);
  803. }
  804. }
  805. }
  806. JSONArray controlIds = jsonResponse.optJSONArray("controlIds");
  807. if (controlIds != null) {
  808. for (int i = 0; i < controlIds.length(); i++) {
  809. try {
  810. JSONObject jsonObject = controlIds.getJSONObject(i);
  811. String spot = jsonObject.getString("conversation");
  812. Integer availableId = jsonObject.getInt("id");
  813. String user = ChatUtils.getOtherSpotUser(spot, IdentityController.getLoggedInUser());
  814. // update available ids
  815. friend = mFriendAdapter.getFriend(user);
  816. if (friend != null) {
  817. friend.setAvailableMessageControlId(availableId);
  818. }
  819. }
  820. catch (JSONException e) {
  821. SurespotLog.w(TAG, "getlatestIds", e);
  822. }
  823. }
  824. }
  825. JSONArray userControlMessages = jsonResponse.optJSONArray("userControlMessages");
  826. if (userControlMessages != null) {
  827. handleControlMessages(IdentityController.getLoggedInUser(), userControlMessages);
  828. }
  829. if (friend != null) {
  830. mFriendAdapter.sort();
  831. mFriendAdapter.notifyDataSetChanged();
  832. }
  833. getLatestMessagesAndControls();
  834. }
  835. @Override
  836. public void onFailure(Throwable error, String content) {
  837. // setMessagesLoading(false);
  838. SurespotLog.i(TAG, error, "loading latest messages failed");
  839. Utils.makeToast(mContext, mContext.getString(R.string.loading_latest_messages_failed));
  840. setProgress(null, false);
  841. }
  842. });
  843. }
  844. private class LatestIdPair {
  845. public int latestMessageId;
  846. public int latestControlMessageId;
  847. }
  848. private void getLatestMessagesAndControls() {
  849. for (Entry<String, ChatAdapter> entry : mChatAdapters.entrySet()) {
  850. getLatestMessagesAndControls(entry.getKey());
  851. }
  852. // done with "global" updates
  853. setProgress(null, false);
  854. }
  855. private LatestIdPair getLatestIds(String username) {
  856. Friend friend = getFriendAdapter().getFriend(username);
  857. LatestIdPair idPair = mPreConnectIds.get(username);
  858. Integer latestMessageId = idPair.latestMessageId > -1 ? idPair.latestMessageId : 0;
  859. int latestAvailableId = friend.getAvailableMessageId();
  860. int latestControlId = idPair.latestControlMessageId > -1 ? idPair.latestControlMessageId : friend.getLastReceivedMessageControlId();
  861. int latestAvailableControlId = friend.getAvailableMessageControlId();
  862. int fetchMessageId = 0;
  863. if (latestMessageId > 0) {
  864. fetchMessageId = latestAvailableId > latestMessageId ? latestMessageId : -1;
  865. }
  866. int fetchControlMessageId = 0;
  867. if (latestControlId > 0) {
  868. fetchControlMessageId = latestAvailableControlId > latestControlId ? latestControlId : -1;
  869. }
  870. LatestIdPair intPair = new LatestIdPair();
  871. intPair.latestMessageId = fetchMessageId;
  872. intPair.latestControlMessageId = fetchControlMessageId;
  873. return intPair;
  874. }
  875. private void getLatestMessagesAndControls(final String username) {
  876. LatestIdPair ids = getLatestIds(username);
  877. getLatestMessagesAndControls(username, ids.latestMessageId, ids.latestControlMessageId);
  878. }
  879. private void getLatestMessagesAndControls(String username, int messageId) {
  880. getLatestMessagesAndControls(username, messageId, -1);
  881. }
  882. private void getLatestMessagesAndControls(final String username, int fetchMessageId, int fetchControlMessageId) {
  883. SurespotLog.v(TAG, "getLatestMessagesAndControls: name %s, fetchMessageId: %d, fetchControlMessageId: %d", username, fetchMessageId,
  884. fetchControlMessageId);
  885. if (fetchMessageId > -1 || fetchControlMessageId > -1) {
  886. setProgress(username, true);
  887. mNetworkController.getMessageData(username, fetchMessageId, fetchControlMessageId, new JsonHttpResponseHandler() {
  888. @Override
  889. public void onSuccess(int statusCode, JSONObject response) {
  890. JSONArray controlMessages = response.optJSONArray("controlMessages");
  891. String messages = response.optString("messages", null);
  892. if (messages != null) {
  893. handleMessages(username, messages);
  894. }
  895. if (controlMessages != null) {
  896. handleControlMessages(username, controlMessages);
  897. }
  898. setProgress(username, false);
  899. }
  900. });
  901. }
  902. }
  903. private void handleControlMessages(String username, JSONArray jsonArray) {
  904. SurespotLog.v(TAG, "%s: handleControlMessages", username);
  905. final ChatAdapter chatAdapter = mChatAdapters.get(username);
  906. SurespotControlMessage message = null;
  907. boolean messageActivity = false;
  908. boolean userActivity = false;
  909. for (int i = 0; i < jsonArray.length(); i++) {
  910. try {
  911. JSONObject jsonMessage = new JSONObject(jsonArray.getString(i));
  912. message = SurespotControlMessage.toSurespotControlMessage(jsonMessage);
  913. handleControlMessage(chatAdapter, message, false, false);
  914. // if it's a system message from another user then check version
  915. if (message.getType().equals("user")) {
  916. userActivity = true;
  917. }
  918. else
  919. if (message.getType().equals("message")) {
  920. messageActivity = true;
  921. }
  922. }
  923. catch (JSONException e) {
  924. SurespotLog.w(TAG, e, "%s: error creating chat message", username);
  925. }
  926. }
  927. if (message != null) {
  928. SurespotLog.v(TAG, "%s: loaded: %d latest control messages from the server.", username, jsonArray.length());
  929. if (messageActivity || userActivity) {
  930. Friend friend = mFriendAdapter.getFriend(username);
  931. if (friend != null) {
  932. if (messageActivity) {
  933. if (chatAdapter != null) {
  934. friend.setLastReceivedMessageControlId(message.getId());
  935. chatAdapter.sort();
  936. chatAdapter.notifyDataSetChanged();
  937. }
  938. friend.setAvailableMessageControlId(message.getId());
  939. mFriendAdapter.notifyDataSetChanged();
  940. }
  941. if (userActivity) {
  942. friend.setLastReceivedUserControlId(message.getId());
  943. saveFriends();
  944. mFriendAdapter.notifyDataSetChanged();
  945. }
  946. }
  947. }
  948. }
  949. // chatAdapter.setLoading(false);
  950. }
  951. private void handleControlMessage(ChatAdapter chatAdapter, SurespotControlMessage message, boolean notify, boolean reApplying) {
  952. // if it's a system message from another user then check version
  953. if (message.getType().equals("user")) {
  954. handleUserControlMessage(message, notify);
  955. }
  956. else
  957. if (message.getType().equals("message")) {
  958. String otherUser = ChatUtils.getOtherSpotUser(message.getData(), IdentityController.getLoggedInUser());
  959. Friend friend = mFriendAdapter.getFriend(otherUser);
  960. if (chatAdapter == null) {
  961. chatAdapter = mChatAdapters.get(otherUser);
  962. }
  963. if (chatAdapter != null) {
  964. // if we're not re applying this control message
  965. if (!reApplying) {
  966. // add control message to check messages against later for this session
  967. chatAdapter.addControlMessage(message);
  968. }
  969. boolean controlFromMe = message.getFrom().equals(IdentityController.getLoggedInUser());
  970. if (message.getAction().equals("delete")) {
  971. int messageId = Integer.parseInt(message.getMoreData());
  972. SurespotMessage dMessage = chatAdapter.getMessageById(messageId);
  973. if (dMessage != null) {
  974. deleteMessageInternal(chatAdapter, dMessage, controlFromMe);
  975. }
  976. }
  977. else {
  978. if (message.getAction().equals("deleteAll")) {
  979. if (message.getMoreData() != null) {
  980. if (controlFromMe) {
  981. chatAdapter.deleteAllMessages(Integer.parseInt(message.getMoreData()));
  982. }
  983. else {
  984. chatAdapter.deleteTheirMessages(Integer.parseInt(message.getMoreData()));
  985. }
  986. }
  987. }
  988. else {
  989. if (message.getAction().equals("shareable") || message.getAction().equals("notshareable")) {
  990. int messageId = Integer.parseInt(message.getMoreData());
  991. SurespotMessage dMessage = chatAdapter.getMessageById(messageId);
  992. if (dMessage != null) {
  993. SurespotLog.v(TAG, "setting message " + message.getAction());
  994. dMessage.setShareable(message.getAction().equals("shareable") ? true : false);
  995. }
  996. }
  997. }
  998. }
  999. }
  1000. if (notify) {
  1001. if (friend != null) {
  1002. // if the chat adapter is open we will have acted upon the control message
  1003. if (chatAdapter != null) {
  1004. friend.setLastReceivedMessageControlId(message.getId());
  1005. }
  1006. friend.setAvailableMessageControlId(message.getId());
  1007. }
  1008. if (chatAdapter != null) {
  1009. chatAdapter.notifyDataSetChanged();
  1010. }
  1011. }
  1012. }
  1013. }
  1014. private void handleUserControlMessage(SurespotControlMessage message, boolean notify) {
  1015. mLatestUserControlId = message.getId();
  1016. String user = null;
  1017. if (message.getAction().equals("revoke")) {
  1018. IdentityController.updateLatestVersion(mContext, message.getData(), message.getMoreData());
  1019. }
  1020. else
  1021. if (message.getAction().equals("invited")) {
  1022. user = message.getData();
  1023. mFriendAdapter.addFriendInvited(user);
  1024. }
  1025. else
  1026. if (message.getAction().equals("added")) {
  1027. user = message.getData();
  1028. mFriendAdapter.addNewFriend(user);
  1029. ChatAdapter chatAdapter = mChatAdapters.get(user);
  1030. if (chatAdapter != null) {
  1031. chatAdapter.userDeleted(false);
  1032. }
  1033. }
  1034. else
  1035. if (message.getAction().equals("invite")) {
  1036. user = message.getData();
  1037. mFriendAdapter.addFriendInviter(user);
  1038. }
  1039. else
  1040. if (message.getAction().equals("ignore")) {
  1041. String friendName = message.getData();
  1042. Friend friend = mFriendAdapter.getFriend(friendName);
  1043. // if they're not deleted, remove them
  1044. if (friend != null) {
  1045. if (!friend.isDeleted()) {
  1046. mFriendAdapter.removeFriend(friendName);
  1047. }
  1048. else {
  1049. // they've been deleted, just remove the invite flags
  1050. friend.setInviter(false);
  1051. friend.setInvited(false);
  1052. }
  1053. }
  1054. }
  1055. else
  1056. if (message.getAction().equals("delete")) {
  1057. String friendName = message.getData();
  1058. Friend friend = mFriendAdapter.getFriend(friendName);
  1059. if (friend != null) {
  1060. // if it was just a delete of an invite
  1061. if (friend.isInviter() || friend.isInvited()) {
  1062. // if they're not deleted, remove them
  1063. if (!friend.isDeleted()) {
  1064. mFriendAdapter.removeFriend(friendName);
  1065. }
  1066. else {
  1067. // they've been deleted, just remove the invite flags
  1068. friend.setInviter(false);
  1069. friend.setInvited(false);
  1070. }
  1071. // clear any associated invite notification
  1072. String loggedInUser = IdentityController.getLoggedInUser();
  1073. if (loggedInUser != null) {
  1074. mNotificationManager.cancel(loggedInUser + ":" + friendName,
  1075. SurespotConstants.IntentRequestCodes.INVITE_REQUEST_NOTIFICATION);
  1076. }
  1077. }
  1078. // they really deleted us boo hoo
  1079. else {
  1080. handleDeleteUser(friendName, message.getMoreData(), notify);
  1081. }
  1082. }
  1083. }
  1084. if (notify) {
  1085. Friend friend = mFriendAdapter.getFriend(user);
  1086. if (friend != null) {
  1087. friend.setLastReceivedUserControlId(message.getId());
  1088. }
  1089. mFriendAdapter.notifyDataSetChanged();
  1090. saveFriends();
  1091. }
  1092. }
  1093. private void handleDeleteUser(String deletedUser, String deleter, boolean notify) {
  1094. SurespotLog.v(TAG, "handleDeleteUser, deletedUser: %s, deleter: %s", deletedUser, deleter);
  1095. String username = IdentityController.getLoggedInUser();
  1096. Friend friend = mFriendAdapter.getFriend(deletedUser);
  1097. boolean iDidTheDeleting = deleter.equals(username);
  1098. if (iDidTheDeleting) {
  1099. // won't be needing this anymore
  1100. closeTab(deletedUser);
  1101. // blow all the state associated with this user away
  1102. StateController.wipeUserState(mContext, username, deletedUser);
  1103. // clear in memory cached data
  1104. SurespotApplication.getCachingService().clearUserData(deletedUser);
  1105. // clear the http cache
  1106. mNetworkController.clearCache();
  1107. // or you
  1108. mFriendAdapter.removeFriend(deletedUser);
  1109. }
  1110. // you deleted me, you bastard!!
  1111. else {
  1112. ChatAdapter chatAdapter = mChatAdapters.get(deleter);
  1113. // i'll delete all your messages then
  1114. if (chatAdapter != null) {
  1115. chatAdapter.userDeleted(true);
  1116. if (notify) {
  1117. chatAdapter.notifyDataSetChanged();
  1118. }
  1119. }
  1120. // and mark you as deleted until I want to delete you
  1121. friend.setDeleted();
  1122. // force the controls to update
  1123. if (friend != null && mCurrentChat != null && mCurrentChat.equals(deletedUser)) {
  1124. mTabShowingCallback.handleResponse(friend);
  1125. }
  1126. }
  1127. enableMenuItems(friend);
  1128. }
  1129. private void handleErrorMessage(SurespotErrorMessage errorMessage) {
  1130. SurespotMessage message = null;
  1131. Iterator<SurespotMessage> iterator = mResendBuffer.iterator();
  1132. while (iterator.hasNext()) {
  1133. message = iterator.next();
  1134. if (message.getIv().equals(errorMessage.getId())) {
  1135. iterator.remove();
  1136. message.setErrorStatus(errorMessage.getStatus());
  1137. break;
  1138. }
  1139. }
  1140. if (message != null) {
  1141. ChatAdapter chatAdapter = mChatAdapters.get(message.getOtherUser());
  1142. if (chatAdapter != null) {
  1143. chatAdapter.notifyDataSetChanged();
  1144. }
  1145. }
  1146. }
  1147. private void deleteMessageInternal(ChatAdapter chatAdapter, SurespotMessage dMessage, boolean initiatedByMe) {
  1148. // if it's an image blow the http cache entry away
  1149. if (dMessage.getMimeType() != null) {
  1150. if (dMessage.getMimeType().equals(SurespotConstants.MimeTypes.IMAGE) || dMessage.getMimeType().equals(SurespotConstants.MimeTypes.M4A)) {
  1151. mNetworkController.purgeCacheUrl(dMessage.getData());
  1152. }
  1153. boolean myMessage = dMessage.getFrom().equals(IdentityController.getLoggedInUser());
  1154. // if i sent the delete, or it's not my message then delete it
  1155. // (if someone else deleted my message we don't care)
  1156. if (initiatedByMe || !myMessage) {
  1157. SurespotLog.v(TAG, "deleting message");
  1158. chatAdapter.deleteMessageById(dMessage.getId());
  1159. }
  1160. }
  1161. }
  1162. private void handleMessages(String username, String jsonMessageString) {
  1163. SurespotLog.v(TAG, "%s: handleMessages", username);
  1164. final ChatAdapter chatAdapter = mChatAdapters.get(username);
  1165. if (chatAdapter == null) {
  1166. return;
  1167. }
  1168. int sentByMeCount = 0;
  1169. SurespotMessage lastMessage = null;
  1170. try {
  1171. JSONArray jsonUM = new JSONArray(jsonMessageString);
  1172. SurespotLog.v(TAG, "%s: loaded: %d messages from the server: %s", username, jsonUM.length(), jsonMessageString);
  1173. for (int i = 0; i < jsonUM.length(); i++) {
  1174. lastMessage = SurespotMessage.toSurespotMessage(new JSONObject(jsonUM.getString(i)));
  1175. boolean myMessage = lastMessage.getFrom().equals(IdentityController.getLoggedInUser());
  1176. if (myMessage) {
  1177. if (lastMessage.getMimeType().equals(SurespotConstants.MimeTypes.IMAGE)) {
  1178. handleCachedFile(chatAdapter, lastMessage);
  1179. }
  1180. else {
  1181. if (lastMessage.getMimeType().equals(SurespotConstants.MimeTypes.M4A)) {
  1182. handleCachedFile(chatAdapter, lastMessage);
  1183. }
  1184. }
  1185. }
  1186. boolean added = applyControlMessages(chatAdapter, lastMessage, false, false, false);
  1187. mResendBuffer.remove(lastMessage);
  1188. if (added && myMessage) {
  1189. sentByMeCount++;
  1190. }
  1191. }
  1192. }
  1193. catch (JSONException e) {
  1194. SurespotLog.w(TAG, e, "jsonStringsToMessages");
  1195. }
  1196. catch (SurespotMessageSequenceException e) {
  1197. // shouldn't happen
  1198. SurespotLog.w(TAG, e, "handleMessages");
  1199. // getLatestMessagesAndControls(username, e.getMessageId(), -1);
  1200. // setProgress(username, false);
  1201. return;
  1202. }
  1203. if (lastMessage != null) {
  1204. Friend friend = mFriendAdapter.getFriend(username);
  1205. int availableId = lastMessage.getId();
  1206. friend.setAvailableMessageId(availableId);
  1207. int lastViewedId = friend.getLastViewedMessageId();
  1208. // how many new messages total are there
  1209. int delta = availableId - lastViewedId;
  1210. // if the current chat is showing or
  1211. // all the new messages are mine then i've viewed them all
  1212. if (username.equals(mCurrentChat) || sentByMeCount == delta) {
  1213. friend.setLastViewedMessageId(availableId);
  1214. }
  1215. else {
  1216. // set the last viewed id to the difference caused by their messages
  1217. friend.setLastViewedMessageId(availableId - (delta - sentByMeCount));
  1218. }
  1219. chatAdapter.sort();
  1220. chatAdapter.notifyDataSetChanged();
  1221. chatAdapter.doneCheckingSequence();
  1222. mFriendAdapter.sort();
  1223. mFriendAdapter.notifyDataSetChanged();
  1224. scrollToEnd(username);
  1225. }
  1226. // setProgress(username, false);
  1227. }
  1228. private Integer getEarliestMessageId(String username) {
  1229. ChatAdapter chatAdapter = mChatAdapters.get(username);
  1230. Integer firstMessageId = null;
  1231. if (chatAdapter != null) {
  1232. SurespotMessage firstMessage = chatAdapter.getFirstMessageWithId();
  1233. if (firstMessage != null) {
  1234. firstMessageId = firstMessage.getId();
  1235. }
  1236. }
  1237. return firstMessageId;
  1238. }
  1239. private int getLatestMessageId(String username) {
  1240. Integer lastMessageId = 0;
  1241. ChatAdapter chatAdapter = mChatAdapters.get(username);
  1242. if (chatAdapter != null) {
  1243. SurespotMessage lastMessage = chatAdapter.getLastMessageWithId();
  1244. if (lastMessage != null) {
  1245. lastMessageId = lastMessage.getId();
  1246. }
  1247. }
  1248. return lastMessageId;
  1249. }
  1250. private Integer getLatestMessageControlId(String username) {
  1251. Friend friend = mFriendAdapter.getFriend(username);
  1252. Integer lastControlId = null;
  1253. if (friend != null) {
  1254. lastControlId = friend.getLastReceivedMessageControlId();
  1255. }
  1256. return lastControlId == null ? 0 : lastControlId;
  1257. }
  1258. public synchronized void loadMessages(String username, boolean replace) {
  1259. SurespotLog.v(TAG, "loadMessages: " + username);
  1260. String loggedInUser = IdentityController.getLoggedInUser();
  1261. if (!TextUtils.isEmpty(loggedInUser)) {
  1262. String spot = ChatUtils.getSpot(loggedInUser, username);
  1263. ChatAdapter chatAdapter = mChatAdapters.get(username);
  1264. if (replace) {
  1265. chatAdapter.setMessages(SurespotApplication.getStateController().loadMessages(spot));
  1266. }
  1267. else {
  1268. chatAdapter.addOrUpdateMessages(SurespotApplication.getStateController().loadMessag

Large files files are truncated, but you can click here to view the full file