1package eu.siacs.conversations.ui;
2
3import android.annotation.SuppressLint;
4import android.support.v7.app.AlertDialog;
5import android.app.FragmentTransaction;
6import android.content.ActivityNotFoundException;
7import android.content.Intent;
8import android.net.Uri;
9import android.os.Build;
10import android.os.Bundle;
11import android.provider.Settings;
12import android.support.v4.widget.SlidingPaneLayout;
13import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener;
14import android.support.v7.app.ActionBar;
15import android.util.Log;
16import android.util.Pair;
17import android.view.KeyEvent;
18import android.view.Menu;
19import android.view.MenuItem;
20import android.view.Surface;
21import android.view.View;
22import android.widget.AdapterView;
23import android.widget.AdapterView.OnItemClickListener;
24import android.widget.ArrayAdapter;
25import android.widget.Toast;
26
27
28import java.util.ArrayList;
29import java.util.List;
30import java.util.concurrent.atomic.AtomicBoolean;
31
32import de.timroes.android.listview.EnhancedListView;
33import eu.siacs.conversations.Config;
34import eu.siacs.conversations.R;
35import eu.siacs.conversations.entities.Account;
36import eu.siacs.conversations.entities.Conversation;
37import eu.siacs.conversations.entities.Message;
38import eu.siacs.conversations.services.XmppConnectionService;
39import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
40import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
41import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
42import eu.siacs.conversations.ui.adapter.ConversationAdapter;
43import eu.siacs.conversations.ui.service.EmojiService;
44import eu.siacs.conversations.utils.ExceptionHelper;
45import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
46import eu.siacs.conversations.xmpp.jid.InvalidJidException;
47import eu.siacs.conversations.xmpp.jid.Jid;
48
49public class ConversationLegacyActivity extends XmppActivity
50 implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast {
51
52 public static final String ACTION_VIEW_CONVERSATION = "eu.siacs.conversations.action.VIEW";
53 public static final String CONVERSATION = "conversationUuid";
54 public static final String EXTRA_DOWNLOAD_UUID = "eu.siacs.conversations.download_uuid";
55 public static final String TEXT = "text";
56 public static final String NICK = "nick";
57 public static final String PRIVATE_MESSAGE = "pm";
58
59 private static final String STATE_OPEN_CONVERSATION = "state_open_conversation";
60 private static final String STATE_PANEL_OPEN = "state_panel_open";
61 private static final String STATE_PENDING_URI = "state_pending_uri";
62 private static final String STATE_FIRST_VISIBLE = "first_visible";
63 private static final String STATE_OFFSET_FROM_TOP = "offset_from_top";
64
65 private String mOpenConversation = null;
66 private boolean mPanelOpen = true;
67 private AtomicBoolean mShouldPanelBeOpen = new AtomicBoolean(false);
68 private Pair<Integer, Integer> mScrollPosition = null;
69 private boolean forbidProcessingPendings = false;
70
71 private boolean conversationWasSelectedByKeyboard = false;
72
73 private View mContentView;
74
75 private List<Conversation> conversationList = new ArrayList<>();
76 private Conversation swipedConversation = null;
77 private Conversation mSelectedConversation = null;
78 private EnhancedListView listView;
79 private ConversationFragment mConversationFragment;
80
81 private ArrayAdapter<Conversation> listAdapter;
82
83 private boolean mActivityPaused = false;
84 private AtomicBoolean mRedirected = new AtomicBoolean(false);
85 private boolean mUnprocessedNewIntent = false;
86
87 public Conversation getSelectedConversation() {
88 return this.mSelectedConversation;
89 }
90
91 public void setSelectedConversation(Conversation conversation) {
92 this.mSelectedConversation = conversation;
93 }
94
95 public void showConversationsOverview() {
96 if (mConversationFragment != null) {
97 mConversationFragment.stopScrolling();
98 }
99 if (mContentView instanceof SlidingPaneLayout) {
100 SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
101 mShouldPanelBeOpen.set(true);
102 mSlidingPaneLayout.openPane();
103 }
104 }
105
106 @Override
107 protected String getShareableUri() {
108 Conversation conversation = getSelectedConversation();
109 if (conversation != null) {
110 return conversation.getAccount().getShareableUri();
111 } else {
112 return "";
113 }
114 }
115
116 public void hideConversationsOverview() {
117 if (mContentView instanceof SlidingPaneLayout) {
118 SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
119 mShouldPanelBeOpen.set(false);
120 mSlidingPaneLayout.closePane();
121 }
122 }
123
124 public boolean isConversationsOverviewHideable() {
125 return mContentView instanceof SlidingPaneLayout;
126 }
127
128 public boolean isConversationsOverviewVisable() {
129 if (mContentView instanceof SlidingPaneLayout) {
130 return mShouldPanelBeOpen.get();
131 } else {
132 return true;
133 }
134 }
135
136 @Override
137 protected void onCreate(final Bundle savedInstanceState) {
138 super.onCreate(savedInstanceState);
139 new EmojiService(this).init();
140 if (savedInstanceState != null) {
141 mOpenConversation = savedInstanceState.getString(STATE_OPEN_CONVERSATION, null);
142 mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
143 int pos = savedInstanceState.getInt(STATE_FIRST_VISIBLE, -1);
144 int offset = savedInstanceState.getInt(STATE_OFFSET_FROM_TOP, 1);
145 if (pos >= 0 && offset <= 0) {
146 Log.d(Config.LOGTAG, "retrieved scroll position from instanceState " + pos + ":" + offset);
147 mScrollPosition = new Pair<>(pos, offset);
148 } else {
149 mScrollPosition = null;
150 }
151 }
152
153 setContentView(R.layout.fragment_conversations_overview);
154
155 this.mConversationFragment = new ConversationFragment();
156 FragmentTransaction transaction = getFragmentManager().beginTransaction();
157 //transaction.replace(R.id.selected_conversation, this.mConversationFragment, "conversation");
158 transaction.commit();
159
160 this.listView = findViewById(R.id.list);
161 this.listAdapter = new ConversationAdapter(this, conversationList);
162 this.listView.setAdapter(this.listAdapter);
163 this.listView.setSwipeDirection(EnhancedListView.SwipeDirection.END);
164
165 final ActionBar actionBar = getSupportActionBar();
166 if (actionBar != null) {
167 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE);
168 }
169
170 listView.setOnItemClickListener(new OnItemClickListener() {
171
172 @Override
173 public void onItemClick(AdapterView<?> arg0, View clickedView,
174 int position, long arg3) {
175 if (getSelectedConversation() != conversationList.get(position)) {
176 ConversationLegacyActivity.this.mConversationFragment.stopScrolling();
177 setSelectedConversation(conversationList.get(position));
178 //ConversationLegacyActivity.this.mConversationFragment.reInit(getSelectedConversation());
179 conversationWasSelectedByKeyboard = false;
180 }
181 hideConversationsOverview();
182 openConversation();
183 }
184 });
185
186 listView.setDismissCallback(new EnhancedListView.OnDismissCallback() {
187
188 @Override
189 public EnhancedListView.Undoable onDismiss(final EnhancedListView enhancedListView, final int position) {
190
191 final int index = listView.getFirstVisiblePosition();
192 View v = listView.getChildAt(0);
193 final int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop());
194
195 try {
196 swipedConversation = listAdapter.getItem(position);
197 } catch (IndexOutOfBoundsException e) {
198 return null;
199 }
200 listAdapter.remove(swipedConversation);
201 xmppConnectionService.markRead(swipedConversation);
202
203 final boolean formerlySelected = (getSelectedConversation() == swipedConversation);
204 if (position == 0 && listAdapter.getCount() == 0) {
205 endConversation(swipedConversation, false, true);
206 return null;
207 } else if (formerlySelected) {
208 setSelectedConversation(listAdapter.getItem(0));
209 //ConversationLegacyActivity.this.mConversationFragment.reInit(getSelectedConversation());
210 }
211
212 return new EnhancedListView.Undoable() {
213
214 @Override
215 public void undo() {
216 listAdapter.insert(swipedConversation, position);
217 if (formerlySelected) {
218 setSelectedConversation(swipedConversation);
219 //ConversationLegacyActivity.this.mConversationFragment.reInit(getSelectedConversation());
220 }
221 swipedConversation = null;
222 listView.setSelectionFromTop(index + (listView.getChildCount() < position ? 1 : 0), top);
223 }
224
225 @Override
226 public void discard() {
227 if (!swipedConversation.isRead()
228 && swipedConversation.getMode() == Conversation.MODE_SINGLE) {
229 swipedConversation = null;
230 return;
231 }
232 endConversation(swipedConversation, false, false);
233 swipedConversation = null;
234 }
235
236 @Override
237 public String getTitle() {
238 if (swipedConversation.getMode() == Conversation.MODE_MULTI) {
239 return getResources().getString(R.string.title_undo_swipe_out_muc);
240 } else {
241 return getResources().getString(R.string.title_undo_swipe_out_conversation);
242 }
243 }
244 };
245 }
246 });
247 listView.enableSwipeToDismiss();
248 listView.setSwipingLayout(R.id.swipeable_item);
249 listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP);
250 listView.setUndoHideDelay(5000);
251 listView.setRequireTouchBeforeDismiss(false);
252
253 //mContentView = findViewById(R.id.content_view_spl);
254 if (mContentView == null) {
255 //mContentView = findViewById(R.id.content_view_ll);
256 }
257 if (mContentView instanceof SlidingPaneLayout) {
258 SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
259 mSlidingPaneLayout.setShadowResource(R.drawable.es_slidingpane_shadow);
260 mSlidingPaneLayout.setSliderFadeColor(0);
261 mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() {
262
263 @Override
264 public void onPanelOpened(View arg0) {
265 mShouldPanelBeOpen.set(true);
266 updateActionBarTitle();
267 invalidateOptionsMenu();
268 hideKeyboard();
269 if (xmppConnectionServiceBound) {
270 xmppConnectionService.getNotificationService().setOpenConversation(null);
271 }
272 closeContextMenu();
273 }
274
275 @Override
276 public void onPanelClosed(View arg0) {
277 mShouldPanelBeOpen.set(false);
278 listView.discardUndo();
279 openConversation();
280 }
281
282 @Override
283 public void onPanelSlide(View arg0, float arg1) {
284 // TODO Auto-generated method stub
285
286 }
287 });
288 }
289 }
290
291 @Override
292 public void switchToConversation(Conversation conversation) {
293 setSelectedConversation(conversation);
294 runOnUiThread(() -> {
295 //ConversationLegacyActivity.this.mConversationFragment.reInit(getSelectedConversation());
296 openConversation();
297 });
298 }
299
300 private void updateActionBarTitle() {
301 updateActionBarTitle(isConversationsOverviewHideable() && !isConversationsOverviewVisable());
302 }
303
304 private void updateActionBarTitle(boolean titleShouldBeName) {
305 final ActionBar ab = getSupportActionBar();
306 final Conversation conversation = getSelectedConversation();
307 if (ab != null) {
308 if (titleShouldBeName && conversation != null) {
309 if ((ab.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != ActionBar.DISPLAY_HOME_AS_UP) {
310 ab.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE);
311 }
312 if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) {
313 ab.setTitle(conversation.getName());
314 } else {
315 ab.setTitle(conversation.getJid().toBareJid().toString());
316 }
317 } else {
318 if ((ab.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) == ActionBar.DISPLAY_HOME_AS_UP) {
319 ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE);
320 }
321 ab.setTitle(R.string.app_name);
322 }
323 }
324 }
325
326 private void openConversation() {
327 this.updateActionBarTitle();
328 this.invalidateOptionsMenu();
329 if (xmppConnectionServiceBound) {
330 final Conversation conversation = getSelectedConversation();
331 xmppConnectionService.getNotificationService().setOpenConversation(conversation);
332 sendReadMarkerIfNecessary(conversation);
333 }
334 listAdapter.notifyDataSetChanged();
335 }
336
337 public void sendReadMarkerIfNecessary(final Conversation conversation) {
338 if (!mActivityPaused && !mUnprocessedNewIntent && conversation != null) {
339 xmppConnectionService.sendReadMarker(conversation);
340 }
341 }
342
343 @Override
344 public boolean onCreateOptionsMenu(Menu menu) {
345 getMenuInflater().inflate(R.menu.activity_conversations, menu);
346 return super.onCreateOptionsMenu(menu);
347 }
348
349 @Override
350 public boolean onOptionsItemSelected(final MenuItem item) {
351 if (item.getItemId() == android.R.id.home) {
352 showConversationsOverview();
353 return true;
354 } else if (item.getItemId() == R.id.action_add) {
355 startActivity(new Intent(this, StartConversationActivity.class));
356 return true;
357 } else {
358 return super.onOptionsItemSelected(item);
359 }
360 }
361
362 public void endConversation(Conversation conversation) {
363 endConversation(conversation, true, true);
364 }
365
366 public void endConversation(Conversation conversation, boolean showOverview, boolean reinit) {
367 if (showOverview) {
368 showConversationsOverview();
369 }
370 xmppConnectionService.archiveConversation(conversation);
371 if (reinit) {
372 if (conversationList.size() > 0) {
373 setSelectedConversation(conversationList.get(0));
374 //this.mConversationFragment.reInit(getSelectedConversation());
375 } else {
376 setSelectedConversation(null);
377 if (mRedirected.compareAndSet(false, true)) {
378 Intent intent = new Intent(this, StartConversationActivity.class);
379 intent.putExtra("init", true);
380 startActivity(intent);
381 finish();
382 }
383 }
384 }
385 }
386
387 @Override
388 public void onBackPressed() {
389 if (!isConversationsOverviewVisable()) {
390 showConversationsOverview();
391 } else {
392 super.onBackPressed();
393 }
394 }
395
396 @Override
397 public boolean onKeyUp(int key, KeyEvent event) {
398 int rotation = getWindowManager().getDefaultDisplay().getRotation();
399 final int upKey;
400 final int downKey;
401 switch (rotation) {
402 case Surface.ROTATION_90:
403 upKey = KeyEvent.KEYCODE_DPAD_LEFT;
404 downKey = KeyEvent.KEYCODE_DPAD_RIGHT;
405 break;
406 case Surface.ROTATION_180:
407 upKey = KeyEvent.KEYCODE_DPAD_DOWN;
408 downKey = KeyEvent.KEYCODE_DPAD_UP;
409 break;
410 case Surface.ROTATION_270:
411 upKey = KeyEvent.KEYCODE_DPAD_RIGHT;
412 downKey = KeyEvent.KEYCODE_DPAD_LEFT;
413 break;
414 case Surface.ROTATION_0:
415 default:
416 upKey = KeyEvent.KEYCODE_DPAD_UP;
417 downKey = KeyEvent.KEYCODE_DPAD_DOWN;
418 }
419 final boolean modifier = event.isCtrlPressed() || (event.getMetaState() & KeyEvent.META_ALT_LEFT_ON) != 0;
420 if (modifier && key == KeyEvent.KEYCODE_TAB && isConversationsOverviewHideable()) {
421 toggleConversationsOverview();
422 return true;
423 } else if (modifier && key == KeyEvent.KEYCODE_SPACE) {
424 startActivity(new Intent(this, StartConversationActivity.class));
425 return true;
426 } else if (modifier && key == downKey) {
427 if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) {
428 showConversationsOverview();
429 ;
430 }
431 return selectDownConversation();
432 } else if (modifier && key == upKey) {
433 if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) {
434 showConversationsOverview();
435 }
436 return selectUpConversation();
437 } else if (modifier && key == KeyEvent.KEYCODE_1) {
438 return openConversationByIndex(0);
439 } else if (modifier && key == KeyEvent.KEYCODE_2) {
440 return openConversationByIndex(1);
441 } else if (modifier && key == KeyEvent.KEYCODE_3) {
442 return openConversationByIndex(2);
443 } else if (modifier && key == KeyEvent.KEYCODE_4) {
444 return openConversationByIndex(3);
445 } else if (modifier && key == KeyEvent.KEYCODE_5) {
446 return openConversationByIndex(4);
447 } else if (modifier && key == KeyEvent.KEYCODE_6) {
448 return openConversationByIndex(5);
449 } else if (modifier && key == KeyEvent.KEYCODE_7) {
450 return openConversationByIndex(6);
451 } else if (modifier && key == KeyEvent.KEYCODE_8) {
452 return openConversationByIndex(7);
453 } else if (modifier && key == KeyEvent.KEYCODE_9) {
454 return openConversationByIndex(8);
455 } else if (modifier && key == KeyEvent.KEYCODE_0) {
456 return openConversationByIndex(9);
457 } else {
458 return super.onKeyUp(key, event);
459 }
460 }
461
462 private void toggleConversationsOverview() {
463 if (isConversationsOverviewVisable()) {
464 hideConversationsOverview();
465 if (mConversationFragment != null) {
466 mConversationFragment.setFocusOnInputField();
467 }
468 } else {
469 showConversationsOverview();
470 }
471 }
472
473 private boolean selectUpConversation() {
474 if (this.mSelectedConversation != null) {
475 int index = this.conversationList.indexOf(this.mSelectedConversation);
476 if (index > 0) {
477 return openConversationByIndex(index - 1);
478 }
479 }
480 return false;
481 }
482
483 private boolean selectDownConversation() {
484 if (this.mSelectedConversation != null) {
485 int index = this.conversationList.indexOf(this.mSelectedConversation);
486 if (index != -1 && index < this.conversationList.size() - 1) {
487 return openConversationByIndex(index + 1);
488 }
489 }
490 return false;
491 }
492
493 private boolean openConversationByIndex(int index) {
494 try {
495 this.conversationWasSelectedByKeyboard = true;
496 this.mConversationFragment.stopScrolling();
497 setSelectedConversation(this.conversationList.get(index));
498 //this.mConversationFragment.reInit(getSelectedConversation());
499 if (index > listView.getLastVisiblePosition() - 1 || index < listView.getFirstVisiblePosition() + 1) {
500 this.listView.setSelection(index);
501 }
502 openConversation();
503 return true;
504 } catch (IndexOutOfBoundsException e) {
505 return false;
506 }
507 }
508
509 @Override
510 protected void onNewIntent(final Intent intent) {
511 if (intent != null && ACTION_VIEW_CONVERSATION.equals(intent.getAction())) {
512 mOpenConversation = null;
513 mUnprocessedNewIntent = true;
514 if (xmppConnectionServiceBound) {
515 handleViewConversationIntent(intent);
516 intent.setAction(Intent.ACTION_MAIN);
517 } else {
518 setIntent(intent);
519 }
520 }
521 }
522
523 @Override
524 public void onStart() {
525 super.onStart();
526 this.mRedirected.set(false);
527 if (this.xmppConnectionServiceBound) {
528 this.onBackendConnected();
529 }
530 if (conversationList.size() >= 1) {
531 this.onConversationUpdate();
532 }
533 }
534
535 @Override
536 public void onPause() {
537 listView.discardUndo();
538 super.onPause();
539 this.mActivityPaused = true;
540 }
541
542 @Override
543 public void onResume() {
544 super.onResume();
545 final int theme = findTheme();
546 final boolean usingEnterKey = usingEnterKey();
547 if (this.mTheme != theme || usingEnterKey != mUsingEnterKey) {
548 recreate();
549 }
550 this.mActivityPaused = false;
551 if (!isConversationsOverviewVisable() || !isConversationsOverviewHideable()) {
552 sendReadMarkerIfNecessary(getSelectedConversation());
553 }
554 }
555
556 @Override
557 public void onSaveInstanceState(final Bundle savedInstanceState) {
558 Conversation conversation = getSelectedConversation();
559 if (conversation != null) {
560 savedInstanceState.putString(STATE_OPEN_CONVERSATION, conversation.getUuid());
561 Pair<Integer, Integer> scrollPosition = mConversationFragment.getScrollPosition();
562 if (scrollPosition != null) {
563 savedInstanceState.putInt(STATE_FIRST_VISIBLE, scrollPosition.first);
564 savedInstanceState.putInt(STATE_OFFSET_FROM_TOP, scrollPosition.second);
565 }
566 } else {
567 savedInstanceState.remove(STATE_OPEN_CONVERSATION);
568 }
569 savedInstanceState.putBoolean(STATE_PANEL_OPEN, isConversationsOverviewVisable());
570 /*if (this.mPendingImageUris.size() >= 1) {
571 Log.d(Config.LOGTAG, "ConversationsActivity.onSaveInstanceState() - saving pending image uri");
572 savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUris.get(0).toString());
573 } else {
574 savedInstanceState.remove(STATE_PENDING_URI);
575 }*/
576 super.onSaveInstanceState(savedInstanceState);
577 }
578
579 private void clearPending() {
580 mConversationFragment.clearPending();
581 }
582
583 private void redirectToStartConversationActivity(boolean noAnimation) {
584 Account pendingAccount = xmppConnectionService.getPendingAccount();
585 if (pendingAccount == null) {
586 Intent startConversationActivity = new Intent(this, StartConversationActivity.class);
587 startConversationActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
588 if (noAnimation) {
589 startConversationActivity.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
590 }
591 startConversationActivity.putExtra("init", true);
592 startActivity(startConversationActivity);
593 if (noAnimation) {
594 overridePendingTransition(0, 0);
595 }
596 } else {
597 switchToAccount(pendingAccount, true);
598 }
599 }
600
601 @Override
602 void onBackendConnected() {
603 this.xmppConnectionService.getNotificationService().setIsInForeground(true);
604 updateConversationList();
605
606 if (mPendingConferenceInvite != null) {
607 if (mPendingConferenceInvite.execute(this)) {
608 mToast = Toast.makeText(this, R.string.creating_conference, Toast.LENGTH_LONG);
609 mToast.show();
610 }
611 mPendingConferenceInvite = null;
612 }
613
614 final Intent intent = getIntent();
615
616 if (xmppConnectionService.getAccounts().size() == 0) {
617 if (mRedirected.compareAndSet(false, true)) {
618 if (Config.X509_VERIFICATION) {
619 Intent redirectionIntent = new Intent(this, ManageAccountActivity.class);
620 redirectionIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
621 startActivity(redirectionIntent);
622 overridePendingTransition(0, 0);
623 } else if (Config.MAGIC_CREATE_DOMAIN != null) {
624 WelcomeActivity.launch(this);
625 } else {
626 Intent editAccount = new Intent(this, EditAccountActivity.class);
627 editAccount.putExtra("init", true);
628 editAccount.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
629 startActivity(editAccount);
630 overridePendingTransition(0, 0);
631 }
632 }
633 } else if (conversationList.size() <= 0) {
634 if (mRedirected.compareAndSet(false, true)) {
635 redirectToStartConversationActivity(true);
636 }
637 } else if (selectConversationByUuid(mOpenConversation)) {
638 if (mPanelOpen) {
639 showConversationsOverview();
640 } else {
641 if (isConversationsOverviewHideable()) {
642 openConversation();
643 updateActionBarTitle(true);
644 }
645 }
646 /*if (this.mConversationFragment.reInit(getSelectedConversation())) {
647 Log.d(Config.LOGTAG, "setting scroll position on fragment");
648 this.mConversationFragment.setScrollPosition(mScrollPosition);
649 }*/
650 mOpenConversation = null;
651 } else if (intent != null && ACTION_VIEW_CONVERSATION.equals(intent.getAction())) {
652 clearPending();
653 handleViewConversationIntent(intent);
654 intent.setAction(Intent.ACTION_MAIN);
655 } else if (getSelectedConversation() == null) {
656 reInitLatestConversation();
657 } else {
658 this.mConversationFragment.messageListAdapter.updatePreferences();
659 //this.mConversationFragment.messagesView.invalidateViews();
660 this.mConversationFragment.setupIme();
661 }
662
663 mConversationFragment.onBackendConnected();
664
665 /*if (!ExceptionHelper.checkForCrash(this, this.xmppConnectionService) && !mRedirected.get()) {
666 openBatteryOptimizationDialogIfNeeded();
667 }*/
668 if (isConversationsOverviewVisable() && isConversationsOverviewHideable()) {
669 xmppConnectionService.getNotificationService().setOpenConversation(null);
670 } else {
671 xmppConnectionService.getNotificationService().setOpenConversation(getSelectedConversation());
672 }
673 }
674
675 private boolean isStopping() {
676 if (Build.VERSION.SDK_INT >= 17) {
677 return isFinishing() || isDestroyed();
678 } else {
679 return isFinishing();
680 }
681 }
682
683 private void reInitLatestConversation() {
684 showConversationsOverview();
685 clearPending();
686 setSelectedConversation(conversationList.get(0));
687 //this.mConversationFragment.reInit(getSelectedConversation());
688 }
689
690 private void handleViewConversationIntent(final Intent intent) {
691 final String uuid = intent.getStringExtra(CONVERSATION);
692 final String downloadUuid = intent.getStringExtra(EXTRA_DOWNLOAD_UUID);
693 final String text = intent.getStringExtra(TEXT);
694 final String nick = intent.getStringExtra(NICK);
695 final boolean pm = intent.getBooleanExtra(PRIVATE_MESSAGE, false);
696 this.mConversationFragment.stopScrolling();
697 if (selectConversationByUuid(uuid)) {
698 /*this.mConversationFragment.reInit(getSelectedConversation());
699 if (nick != null) {
700 if (pm) {
701 Jid jid = getSelectedConversation().getJid();
702 try {
703 Jid next = Jid.fromParts(jid.getLocalpart(), jid.getDomainpart(), nick);
704 this.mConversationFragment.privateMessageWith(next);
705 } catch (final InvalidJidException ignored) {
706 //do nothing
707 }
708 } else {
709 this.mConversationFragment.highlightInConference(nick);
710 }
711 } else {
712 this.mConversationFragment.appendText(text);
713 }
714 hideConversationsOverview();
715 mUnprocessedNewIntent = false;
716 openConversation();
717 if (mContentView instanceof SlidingPaneLayout) {
718 updateActionBarTitle(true); //fixes bug where slp isn't properly closed yet
719 }
720 if (downloadUuid != null) {
721 final Message message = mSelectedConversation.findMessageWithFileAndUuid(downloadUuid);
722 if (message != null) {
723 //startDownloadable(message);
724 }
725 }*/
726 } else {
727 mUnprocessedNewIntent = false;
728 }
729 }
730
731 private boolean selectConversationByUuid(String uuid) {
732 if (uuid == null) {
733 return false;
734 }
735 for (Conversation aConversationList : conversationList) {
736 if (aConversationList.getUuid().equals(uuid)) {
737 setSelectedConversation(aConversationList);
738 return true;
739 }
740 }
741 return false;
742 }
743
744 @Override
745 protected void unregisterListeners() {
746 super.unregisterListeners();
747 xmppConnectionService.getNotificationService().setOpenConversation(null);
748 }
749
750 @Override
751 protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
752 super.onActivityResult(requestCode, resultCode, data);
753 if (resultCode != RESULT_OK) {
754 if (requestCode == REQUEST_BATTERY_OP) {
755 setNeverAskForBatteryOptimizationsAgain();
756 }
757 }
758 }
759
760 private String getBatteryOptimizationPreferenceKey() {
761 @SuppressLint("HardwareIds") String device = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
762 return "show_battery_optimization" + (device == null ? "" : device);
763 }
764
765 private void setNeverAskForBatteryOptimizationsAgain() {
766 getPreferences().edit().putBoolean(getBatteryOptimizationPreferenceKey(), false).apply();
767 }
768
769 private void openBatteryOptimizationDialogIfNeeded() {
770 if (hasAccountWithoutPush()
771 && isOptimizingBattery()
772 && getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true)) {
773 AlertDialog.Builder builder = new AlertDialog.Builder(this);
774 builder.setTitle(R.string.battery_optimizations_enabled);
775 builder.setMessage(R.string.battery_optimizations_enabled_dialog);
776 builder.setPositiveButton(R.string.next, (dialog, which) -> {
777 Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
778 Uri uri = Uri.parse("package:" + getPackageName());
779 intent.setData(uri);
780 try {
781 startActivityForResult(intent, REQUEST_BATTERY_OP);
782 } catch (ActivityNotFoundException e) {
783 Toast.makeText(this, R.string.device_does_not_support_battery_op, Toast.LENGTH_SHORT).show();
784 }
785 });
786 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
787 builder.setOnDismissListener(dialog -> setNeverAskForBatteryOptimizationsAgain());
788 }
789 AlertDialog dialog = builder.create();
790 dialog.setCanceledOnTouchOutside(false);
791 dialog.show();
792 }
793 }
794
795 private boolean hasAccountWithoutPush() {
796 for (Account account : xmppConnectionService.getAccounts()) {
797 if (account.getStatus() == Account.State.ONLINE && !xmppConnectionService.getPushManagementService().available(account)) {
798 return true;
799 }
800 }
801 return false;
802 }
803
804 public void updateConversationList() {
805 xmppConnectionService.populateWithOrderedConversations(conversationList);
806 if (!conversationList.contains(mSelectedConversation)) {
807 mSelectedConversation = null;
808 }
809 if (swipedConversation != null) {
810 if (swipedConversation.isRead()) {
811 conversationList.remove(swipedConversation);
812 } else {
813 listView.discardUndo();
814 }
815 }
816 listAdapter.notifyDataSetChanged();
817 }
818
819 @Override
820 protected void refreshUiReal() {
821 updateConversationList();
822 if (conversationList.size() > 0) {
823 if (!this.mConversationFragment.isAdded()) {
824 Log.d(Config.LOGTAG, "fragment NOT added to activity. detached=" + Boolean.toString(mConversationFragment.isDetached()));
825 }
826 if (getSelectedConversation() == null) {
827 reInitLatestConversation();
828 } else {
829 ConversationLegacyActivity.this.mConversationFragment.refresh();
830 updateActionBarTitle();
831 invalidateOptionsMenu();
832 }
833 } else {
834 if (!isStopping() && mRedirected.compareAndSet(false, true)) {
835 redirectToStartConversationActivity(false);
836 }
837 Log.d(Config.LOGTAG, "not updating conversations fragment because conversations list size was 0");
838 }
839 }
840
841 @Override
842 public void onAccountUpdate() {
843 this.refreshUi();
844 }
845
846 @Override
847 public void onConversationUpdate() {
848 this.refreshUi();
849 }
850
851 @Override
852 public void onRosterUpdate() {
853 this.refreshUi();
854 }
855
856 @Override
857 public void OnUpdateBlocklist(Status status) {
858 this.refreshUi();
859 }
860
861 @Override
862 public void onShowErrorToast(final int resId) {
863 runOnUiThread(() -> Toast.makeText(ConversationLegacyActivity.this, resId, Toast.LENGTH_SHORT).show());
864 }
865
866 public boolean highlightSelectedConversations() {
867 return !isConversationsOverviewHideable() || this.conversationWasSelectedByKeyboard;
868 }
869}