ConversationLegacyActivity.java

  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}