/* * This is the source code of Telegram for Android v. 6.x.x. * It is licensed under GNU GPL v. 2 or later. * You should have received a copy of the license in this archive (see LICENSE). * * Copyright Nikolai Kudashov, 2013-2020. */ package org.telegram.ui; import android.Manifest; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.os.SystemClock; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.RelativeLayout; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ContactsController; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.LocaleController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.camera.CameraController; import org.telegram.ui.ActionBar.ActionBarLayout; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.DrawerLayoutContainer; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.PasscodeView; import org.telegram.ui.Components.ThemeEditorView; import java.util.ArrayList; public class BubbleActivity extends Activity implements ActionBarLayout.ActionBarLayoutDelegate { private boolean finished; private ArrayList mainFragmentsStack = new ArrayList<>(); private PasscodeView passcodeView; private ActionBarLayout actionBarLayout; protected DrawerLayoutContainer drawerLayoutContainer; private Intent passcodeSaveIntent; private boolean passcodeSaveIntentIsNew; private int passcodeSaveIntentAccount; private int passcodeSaveIntentState; private boolean passcodeSaveIntentIsRestore; private Runnable lockRunnable; private long dialogId; private int currentAccount = -1; @Override protected void onCreate(Bundle savedInstanceState) { ApplicationLoader.postInitApplication(); requestWindowFeature(Window.FEATURE_NO_TITLE); setTheme(R.style.Theme_TMessages); getWindow().setBackgroundDrawableResource(R.drawable.transparent); if (SharedConfig.passcodeHash.length() > 0 && !SharedConfig.allowScreenCapture) { try { getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); } catch (Exception e) { FileLog.e(e); } } super.onCreate(savedInstanceState); if (SharedConfig.passcodeHash.length() != 0 && SharedConfig.appLocked) { SharedConfig.lastPauseTime = (int) (SystemClock.elapsedRealtime() / 1000); } AndroidUtilities.fillStatusBarHeight(this); Theme.createDialogsResources(this); Theme.createChatResources(this, false); actionBarLayout = new ActionBarLayout(this); actionBarLayout.setInBubbleMode(true); actionBarLayout.setRemoveActionBarExtraHeight(true); drawerLayoutContainer = new DrawerLayoutContainer(this); drawerLayoutContainer.setAllowOpenDrawer(false, false); setContentView(drawerLayoutContainer, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); RelativeLayout launchLayout = new RelativeLayout(this); drawerLayoutContainer.addView(launchLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); launchLayout.addView(actionBarLayout, LayoutHelper.createRelative(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); drawerLayoutContainer.setParentActionBarLayout(actionBarLayout); actionBarLayout.setDrawerLayoutContainer(drawerLayoutContainer); actionBarLayout.init(mainFragmentsStack); actionBarLayout.setDelegate(this); passcodeView = new PasscodeView(this); drawerLayoutContainer.addView(passcodeView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.closeOtherAppActivities, this); actionBarLayout.removeAllFragments(); handleIntent(getIntent(), false, savedInstanceState != null, false, UserConfig.selectedAccount, 0); } private void showPasscodeActivity() { if (passcodeView == null) { return; } SharedConfig.appLocked = true; if (SecretMediaViewer.hasInstance() && SecretMediaViewer.getInstance().isVisible()) { SecretMediaViewer.getInstance().closePhoto(false, false); } else if (PhotoViewer.hasInstance() && PhotoViewer.getInstance().isVisible()) { PhotoViewer.getInstance().closePhoto(false, true); } else if (ArticleViewer.hasInstance() && ArticleViewer.getInstance().isVisible()) { ArticleViewer.getInstance().close(false, true); } passcodeView.onShow(true, false); SharedConfig.isWaitingForPasscodeEnter = true; drawerLayoutContainer.setAllowOpenDrawer(false, false); passcodeView.setDelegate(() -> { SharedConfig.isWaitingForPasscodeEnter = false; if (passcodeSaveIntent != null) { handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true, passcodeSaveIntentAccount, passcodeSaveIntentState); passcodeSaveIntent = null; } drawerLayoutContainer.setAllowOpenDrawer(true, false); actionBarLayout.showLastFragment(); }); } private boolean handleIntent(final Intent intent, final boolean isNew, final boolean restore, final boolean fromPassword, final int intentAccount, int state) { if (!fromPassword && (AndroidUtilities.needShowPasscode(true) || SharedConfig.isWaitingForPasscodeEnter)) { showPasscodeActivity(); passcodeSaveIntent = intent; passcodeSaveIntentIsNew = isNew; passcodeSaveIntentIsRestore = restore; passcodeSaveIntentAccount = intentAccount; passcodeSaveIntentState = state; UserConfig.getInstance(intentAccount).saveConfig(false); return false; } currentAccount = intent.getIntExtra("currentAccount", UserConfig.selectedAccount); if (!UserConfig.isValidAccount(currentAccount)) { finish(); return false; } BaseFragment chatActivity = null; if (intent.getAction() != null && intent.getAction().startsWith("com.tmessages.openchat")) { long chatId = intent.getLongExtra("chatId", 0); long userId = intent.getLongExtra("userId", 0); Bundle args = new Bundle(); if (userId != 0) { dialogId = userId; args.putLong("user_id", userId); } else { dialogId = -chatId; args.putLong("chat_id", chatId); } chatActivity = new ChatActivity(args); chatActivity.setInBubbleMode(true); chatActivity.setCurrentAccount(currentAccount); } if (chatActivity == null) { finish(); return false; } NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats, dialogId); actionBarLayout.removeAllFragments(); actionBarLayout.addFragmentToStack(chatActivity); AccountInstance.getInstance(currentAccount).getNotificationsController().setOpenedInBubble(dialogId, true); AccountInstance.getInstance(currentAccount).getConnectionsManager().setAppPaused(false, false); actionBarLayout.showLastFragment(); return true; } @Override public boolean onPreIme() { return false; } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); handleIntent(intent, true, false, false, UserConfig.selectedAccount, 0); } private void onFinish() { if (finished) { return; } if (lockRunnable != null) { AndroidUtilities.cancelRunOnUIThread(lockRunnable); lockRunnable = null; } finished = true; } public void presentFragment(BaseFragment fragment) { actionBarLayout.presentFragment(fragment); } public boolean presentFragment(final BaseFragment fragment, final boolean removeLast, boolean forceWithoutAnimation) { return actionBarLayout.presentFragment(fragment, removeLast, forceWithoutAnimation, true, false); } @Override protected void onPause() { super.onPause(); actionBarLayout.onPause(); ApplicationLoader.externalInterfacePaused = true; onPasscodePause(); if (passcodeView != null) { passcodeView.onPause(); } } @Override protected void onDestroy() { super.onDestroy(); if (currentAccount != -1) { AccountInstance.getInstance(currentAccount).getNotificationsController().setOpenedInBubble(dialogId, false); AccountInstance.getInstance(currentAccount).getConnectionsManager().setAppPaused(false, false); } onFinish(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); ThemeEditorView editorView = ThemeEditorView.getInstance(); if (editorView != null) { editorView.onActivityResult(requestCode, resultCode, data); } if (actionBarLayout.fragmentsStack.size() != 0) { BaseFragment fragment = actionBarLayout.fragmentsStack.get(actionBarLayout.fragmentsStack.size() - 1); fragment.onActivityResultFragment(requestCode, resultCode, data); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (grantResults == null) { grantResults = new int[0]; } if (permissions == null) { permissions = new String[0]; } boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; if (requestCode == 104) { if (granted) { if (GroupCallActivity.groupCallInstance != null) { GroupCallActivity.groupCallInstance.enableCamera(); } } else { showPermissionErrorAlert(LocaleController.getString("VoipNeedCameraPermission", R.string.VoipNeedCameraPermission)); } } else if (requestCode == 4) { if (!granted) { showPermissionErrorAlert(LocaleController.getString("PermissionStorage", R.string.PermissionStorage)); } else { ImageLoader.getInstance().checkMediaPaths(); } } else if (requestCode == 5) { if (!granted) { showPermissionErrorAlert(LocaleController.getString("PermissionContacts", R.string.PermissionContacts)); return; } else { ContactsController.getInstance(currentAccount).forceImportContacts(); } } else if (requestCode == 3) { boolean audioGranted = true; boolean cameraGranted = true; for (int i = 0, size = Math.min(permissions.length, grantResults.length); i < size; i++) { if (Manifest.permission.RECORD_AUDIO.equals(permissions[i])) { audioGranted = grantResults[i] == PackageManager.PERMISSION_GRANTED; } else if (Manifest.permission.CAMERA.equals(permissions[i])) { cameraGranted = grantResults[i] == PackageManager.PERMISSION_GRANTED; } } if (!audioGranted) { showPermissionErrorAlert(LocaleController.getString("PermissionNoAudio", R.string.PermissionNoAudio)); } else if (!cameraGranted) { showPermissionErrorAlert(LocaleController.getString("PermissionNoCamera", R.string.PermissionNoCamera)); } else { if (SharedConfig.inappCamera) { CameraController.getInstance().initCamera(null); } return; } } else if (requestCode == 18 || requestCode == 19 || requestCode == 20 || requestCode == 22) { if (!granted) { showPermissionErrorAlert(LocaleController.getString("PermissionNoCamera", R.string.PermissionNoCamera)); } } else if (requestCode == 2) { if (granted) { NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.locationPermissionGranted); } } if (actionBarLayout.fragmentsStack.size() != 0) { BaseFragment fragment = actionBarLayout.fragmentsStack.get(actionBarLayout.fragmentsStack.size() - 1); fragment.onRequestPermissionsResultFragment(requestCode, permissions, grantResults); } VoIPFragment.onRequestPermissionsResult(requestCode, permissions, grantResults); } private void showPermissionErrorAlert(String message) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(message); builder.setNegativeButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), (dialog, which) -> { try { Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.parse("package:" + ApplicationLoader.applicationContext.getPackageName())); startActivity(intent); } catch (Exception e) { FileLog.e(e); } }); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); builder.show(); } @Override protected void onResume() { super.onResume(); actionBarLayout.onResume(); ApplicationLoader.externalInterfacePaused = false; onPasscodeResume(); if (passcodeView.getVisibility() != View.VISIBLE) { actionBarLayout.onResume(); } else { actionBarLayout.dismissDialogs(); passcodeView.onResume(); } } private void onPasscodePause() { if (lockRunnable != null) { AndroidUtilities.cancelRunOnUIThread(lockRunnable); lockRunnable = null; } if (SharedConfig.passcodeHash.length() != 0) { SharedConfig.lastPauseTime = (int) (SystemClock.elapsedRealtime() / 1000); lockRunnable = new Runnable() { @Override public void run() { if (lockRunnable == this) { if (AndroidUtilities.needShowPasscode(true)) { if (BuildVars.LOGS_ENABLED) { FileLog.d("lock app"); } showPasscodeActivity(); } else { if (BuildVars.LOGS_ENABLED) { FileLog.d("didn't pass lock check"); } } lockRunnable = null; } } }; if (SharedConfig.appLocked) { AndroidUtilities.runOnUIThread(lockRunnable, 1000); } else if (SharedConfig.autoLockIn != 0) { AndroidUtilities.runOnUIThread(lockRunnable, (long) SharedConfig.autoLockIn * 1000 + 1000); } } else { SharedConfig.lastPauseTime = 0; } SharedConfig.saveConfig(); } private void onPasscodeResume() { if (lockRunnable != null) { AndroidUtilities.cancelRunOnUIThread(lockRunnable); lockRunnable = null; } if (AndroidUtilities.needShowPasscode(true)) { showPasscodeActivity(); } if (SharedConfig.lastPauseTime != 0) { SharedConfig.lastPauseTime = 0; SharedConfig.saveConfig(); } } @Override public void onConfigurationChanged(android.content.res.Configuration newConfig) { AndroidUtilities.checkDisplaySize(this, newConfig); super.onConfigurationChanged(newConfig); } @Override public void onBackPressed() { if (mainFragmentsStack.size() == 1) { super.onBackPressed(); return; } if (passcodeView.getVisibility() == View.VISIBLE) { finish(); return; } if (PhotoViewer.getInstance().isVisible()) { PhotoViewer.getInstance().closePhoto(true, false); } else if (drawerLayoutContainer.isDrawerOpened()) { drawerLayoutContainer.closeDrawer(false); } else { actionBarLayout.onBackPressed(); } } @Override public void onLowMemory() { super.onLowMemory(); actionBarLayout.onLowMemory(); } @Override public boolean needPresentFragment(BaseFragment fragment, boolean removeLast, boolean forceWithoutAnimation, ActionBarLayout layout) { return true; } @Override public boolean needAddFragmentToStack(BaseFragment fragment, ActionBarLayout layout) { return true; } @Override public boolean needCloseLastFragment(ActionBarLayout layout) { if (layout.fragmentsStack.size() <= 1) { onFinish(); finish(); return false; } return true; } @Override public void onRebuildAllFragments(ActionBarLayout layout, boolean last) { } }