package org.thoughtcrime.securesms; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.view.ViewTreeObserver; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.lifecycle.ViewModelProvider; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import org.signal.core.util.concurrent.LifecycleDisposable; import org.thoughtcrime.securesms.components.DebugLogsPromptDialogFragment; import org.thoughtcrime.securesms.components.PromptBatterySaverDialogFragment; import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController; import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner; import org.thoughtcrime.securesms.conversationlist.RelinkDevicesReminderBottomSheetFragment; import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceExitActivity; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.net.DeviceTransferBlockingInterceptor; import org.thoughtcrime.securesms.notifications.VitalsViewModel; import org.thoughtcrime.securesms.stories.tabs.ConversationListTabRepository; import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel; import org.thoughtcrime.securesms.util.AppStartup; import org.thoughtcrime.securesms.util.CachedInflater; import org.thoughtcrime.securesms.util.CommunicationActions; import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme; import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.SplashScreenUtil; import org.thoughtcrime.securesms.util.WindowUtil; public class MainActivity extends PassphraseRequiredActivity implements VoiceNoteMediaControllerOwner { public static final int RESULT_CONFIG_CHANGED = Activity.RESULT_FIRST_USER + 901; private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme(); private final MainNavigator navigator = new MainNavigator(this); private VoiceNoteMediaController mediaController; private ConversationListTabsViewModel conversationListTabsViewModel; private VitalsViewModel vitalsViewModel; private final LifecycleDisposable lifecycleDisposable = new LifecycleDisposable(); private boolean onFirstRender = false; public static @NonNull Intent clearTop(@NonNull Context context) { Intent intent = new Intent(context, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); return intent; } @Override protected void onCreate(Bundle savedInstanceState, boolean ready) { AppStartup.getInstance().onCriticalRenderEventStart(); super.onCreate(savedInstanceState, ready); setContentView(R.layout.main_activity); final View content = findViewById(android.R.id.content); content.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { // Use pre draw listener to delay drawing frames till conversation list is ready if (onFirstRender) { content.getViewTreeObserver().removeOnPreDrawListener(this); return true; } else { return false; } } }); lifecycleDisposable.bindTo(this); mediaController = new VoiceNoteMediaController(this, true); ConversationListTabRepository repository = new ConversationListTabRepository(); ConversationListTabsViewModel.Factory factory = new ConversationListTabsViewModel.Factory(repository); handleGroupLinkInIntent(getIntent()); handleProxyInIntent(getIntent()); handleSignalMeIntent(getIntent()); handleCallLinkInIntent(getIntent()); CachedInflater.from(this).clear(); conversationListTabsViewModel = new ViewModelProvider(this, factory).get(ConversationListTabsViewModel.class); updateTabVisibility(); vitalsViewModel = new ViewModelProvider(this).get(VitalsViewModel.class); lifecycleDisposable.add( vitalsViewModel .getVitalsState() .subscribe(this::presentVitalsState) ); } @SuppressLint("NewApi") private void presentVitalsState(VitalsViewModel.State state) { switch (state) { case NONE: break; case PROMPT_BATTERY_SAVER_DIALOG: PromptBatterySaverDialogFragment.show(getSupportFragmentManager()); break; case PROMPT_DEBUGLOGS_FOR_NOTIFICATIONS: DebugLogsPromptDialogFragment.show(this, getSupportFragmentManager(), DebugLogsPromptDialogFragment.Purpose.NOTIFICATIONS); case PROMPT_DEBUGLOGS_FOR_CRASH: DebugLogsPromptDialogFragment.show(this, getSupportFragmentManager(), DebugLogsPromptDialogFragment.Purpose.CRASH); break; } } @Override public Intent getIntent() { return super.getIntent().setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); handleGroupLinkInIntent(intent); handleProxyInIntent(intent); handleSignalMeIntent(intent); handleCallLinkInIntent(intent); } @Override protected void onPreCreate() { super.onPreCreate(); dynamicTheme.onCreate(this); } @Override protected void onResume() { super.onResume(); dynamicTheme.onResume(this); if (SignalStore.misc().isOldDeviceTransferLocked()) { new MaterialAlertDialogBuilder(this) .setTitle(R.string.OldDeviceTransferLockedDialog__complete_registration_on_your_new_device) .setMessage(R.string.OldDeviceTransferLockedDialog__your_signal_account_has_been_transferred_to_your_new_device) .setPositiveButton(R.string.OldDeviceTransferLockedDialog__done, (d, w) -> OldDeviceExitActivity.exit(this)) .setNegativeButton(R.string.OldDeviceTransferLockedDialog__cancel_and_activate_this_device, (d, w) -> { SignalStore.misc().clearOldDeviceTransferLocked(); DeviceTransferBlockingInterceptor.getInstance().unblockNetwork(); }) .setCancelable(false) .show(); } if (SignalStore.misc().getShouldShowLinkedDevicesReminder()) { SignalStore.misc().setShouldShowLinkedDevicesReminder(false); RelinkDevicesReminderBottomSheetFragment.show(getSupportFragmentManager()); } updateTabVisibility(); vitalsViewModel.checkSlowNotificationHeuristics(); } @Override protected void onStop() { super.onStop(); SplashScreenUtil.setSplashScreenThemeIfNecessary(this, SignalStore.settings().getTheme()); } @Override public void onBackPressed() { if (!navigator.onBackPressed()) { super.onBackPressed(); } } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == MainNavigator.REQUEST_CONFIG_CHANGES && resultCode == RESULT_CONFIG_CHANGED) { recreate(); } } private void updateTabVisibility() { findViewById(R.id.conversation_list_tabs).setVisibility(View.VISIBLE); WindowUtil.setNavigationBarColor(this, ContextCompat.getColor(this, R.color.signal_colorSurface2)); } public @NonNull MainNavigator getNavigator() { return navigator; } private void handleGroupLinkInIntent(Intent intent) { Uri data = intent.getData(); if (data != null) { CommunicationActions.handlePotentialGroupLinkUrl(this, data.toString()); } } private void handleProxyInIntent(Intent intent) { Uri data = intent.getData(); if (data != null) { CommunicationActions.handlePotentialProxyLinkUrl(this, data.toString()); } } private void handleSignalMeIntent(Intent intent) { Uri data = intent.getData(); if (data != null) { CommunicationActions.handlePotentialSignalMeUrl(this, data.toString()); } } private void handleCallLinkInIntent(Intent intent) { Uri data = intent.getData(); if (data != null) { CommunicationActions.handlePotentialCallLinkUrl(this, data.toString()); } } public void onFirstRender() { onFirstRender = true; } @Override public @NonNull VoiceNoteMediaController getVoiceNoteMediaController() { return mediaController; } }