diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java index a350abf487a..28f30b02f02 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java @@ -32,6 +32,7 @@ import androidx.collection.LongSparseArray; import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; @@ -397,7 +398,7 @@ public void checkAppAccount() { boolean found = false; for (int b = 0; b < UserConfig.MAX_ACCOUNT_COUNT; b++) { TLRPC.User user = UserConfig.getInstance(b).getCurrentUser(); - if (user != null) { + if (user != null && HiddenAccountHelper.isVisibleActivatedAccount(b)) { if (acc.name.equals("" + user.id)) { if (b == currentAccount) { systemAccount = acc; @@ -419,7 +420,7 @@ public void checkAppAccount() { } catch (Throwable ignore) { } - if (getUserConfig().isClientActivated()) { + if (HiddenAccountHelper.isVisibleActivatedAccount(currentAccount)) { readContacts(); if (systemAccount == null) { try { @@ -443,7 +444,7 @@ public void deleteUnknownAppAccounts() { boolean found = false; for (int b = 0; b < UserConfig.MAX_ACCOUNT_COUNT; b++) { TLRPC.User user = UserConfig.getInstance(b).getCurrentUser(); - if (user != null) { + if (user != null && HiddenAccountHelper.isVisibleActivatedAccount(b)) { if (acc.name.equals("" + user.id)) { found = true; break; @@ -530,11 +531,13 @@ public void deleteAllContacts(final Runnable runnable) { } catch (Throwable ignore) { } - try { - systemAccount = new Account("" + getUserConfig().getClientUserId(), "org.telegram.messenger"); - am.addAccountExplicitly(systemAccount, "", null); - } catch (Exception ignore) { + if (HiddenAccountHelper.isVisibleActivatedAccount(currentAccount)) { + try { + systemAccount = new Account("" + getUserConfig().getClientUserId(), "org.telegram.messenger"); + am.addAccountExplicitly(systemAccount, "", null); + } catch (Exception ignore) { + } } getMessagesStorage().putCachedPhoneBook(new HashMap<>(), false, true); getMessagesStorage().putContacts(new ArrayList<>(), true); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java index 3745255963b..026f78f99d2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -66,6 +66,7 @@ import com.google.common.collect.Lists; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.messenger.support.LongSparseIntArray; import org.telegram.messenger.utils.tlutils.TlUtils; import org.telegram.messenger.voip.VoIPGroupNotification; @@ -1719,7 +1720,7 @@ public void processLoadedUnreadMessages(LongSparseArray dialogs, ArrayL private int getTotalAllUnreadCount() { int count = 0; for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { - if (!UserConfig.getInstance(a).isClientActivated() || !SharedConfig.showNotificationsForAllAccounts && UserConfig.selectedAccount != a) { + if (!UserConfig.getInstance(a).isClientActivated() || HiddenAccountHelper.isAccountHidden(a) || !SharedConfig.showNotificationsForAllAccounts && UserConfig.selectedAccount != a) { continue; } NotificationsController controller = getInstance(a); @@ -4063,7 +4064,7 @@ private String validateChannelId(long dialogId, long topicId, String name, long[ } private void showOrUpdateNotification(boolean notifyAboutLast) { - if (!getUserConfig().isClientActivated() || pushMessages.isEmpty() && storyPushMessages.isEmpty() || !SharedConfig.showNotificationsForAllAccounts && currentAccount != UserConfig.selectedAccount) { + if (!getUserConfig().isClientActivated() || HiddenAccountHelper.isAccountHidden(currentAccount) || pushMessages.isEmpty() && storyPushMessages.isEmpty() || !SharedConfig.showNotificationsForAllAccounts && currentAccount != UserConfig.selectedAccount) { dismissNotification(); return; } @@ -4232,7 +4233,7 @@ private void showOrUpdateNotification(boolean notifyAboutLast) { String detailText; if (allowSummary) { - if (UserConfig.getActivatedAccountsCount() > 1) { + if (UserConfig.getVisibleAccountsCount() > 1) { if (pushDialogs.size() == 1) { detailText = UserObject.getFirstName(getUserConfig().getCurrentUser()); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java index e9412f86ac5..4362ee53b65 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java @@ -18,6 +18,7 @@ import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLRPC; import org.telegram.tgnet.tl.TL_account; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import java.util.Arrays; @@ -108,6 +109,10 @@ public static int getActivatedAccountsCount() { return count; } + public static int getVisibleAccountsCount() { + return HiddenAccountHelper.getVisibleAccountsCount(); + } + public UserConfig(int instance) { super(instance); } @@ -460,6 +465,7 @@ public void updateSaveGalleryExceptions(int type, LongSparseArray= 0 && account < UserConfig.MAX_ACCOUNT_COUNT && hasHiddenAccount(account); + } + + public static boolean isVisibleActivatedAccount(int account) { + return UserConfig.isValidAccount(account) && UserConfig.getInstance(account).isClientActivated() && !isAccountHidden(account); + } + + public static boolean hasAnyHiddenAccounts() { + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + if (UserConfig.getInstance(a).isClientActivated() && isAccountHidden(a)) { + return true; + } + } + return false; + } + + public static int getHiddenAccountsCount() { + int count = 0; + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + if (UserConfig.getInstance(a).isClientActivated() && isAccountHidden(a)) { + count++; + } + } + return count; + } + + public static int getVisibleAccountsCount() { + int count = 0; + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + if (isVisibleActivatedAccount(a)) { + count++; + } + } + return count; + } + + public static int getVisibleAccountsCountExcluding(int account) { + int count = 0; + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + if (a != account && isVisibleActivatedAccount(a)) { + count++; + } + } + return count; + } + + public static void collectVisibleAccountNumbers(ArrayList out) { + collectVisibleAccountNumbers(out, -1, null); + } + + public static void collectVisibleAccountNumbers(ArrayList out, int excludedAccount) { + collectVisibleAccountNumbers(out, excludedAccount, null); + } + + public static void collectVisibleAccountNumbers(ArrayList out, int excludedAccount, Boolean testBackend) { + out.clear(); + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + if (a == excludedAccount || !isVisibleActivatedAccount(a)) { + continue; + } + if (testBackend != null && ConnectionsManager.getInstance(a).isTestBackend() != testBackend) { + continue; + } + out.add(a); + } + out.sort((o1, o2) -> Long.compare(UserConfig.getInstance(o1).loginTime, UserConfig.getInstance(o2).loginTime)); + } + + public static boolean canHideAccount(int account) { + return isAccountHidden(account) || getVisibleAccountsCountExcluding(account) > 0; + } + + public static int getFallbackVisibleAccount(int excludedAccount) { + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + if (a != excludedAccount && isVisibleActivatedAccount(a)) { + return a; + } + } + return -1; + } + + public static synchronized void setUnlockedHiddenAccount(int account) { + unlockedHiddenAccount = isAccountHidden(account) ? account : -1; + pendingUnlockAccount = -1; + } + + public static synchronized boolean isUnlockedHiddenAccount(int account) { + return unlockedHiddenAccount == account && isAccountHidden(account); + } + + public static synchronized void clearUnlockedHiddenAccount() { + unlockedHiddenAccount = -1; + pendingUnlockAccount = -1; + } + + public static synchronized void queuePendingUnlock(int account) { + pendingUnlockAccount = isAccountHidden(account) ? account : -1; + } + + public static synchronized int consumePendingUnlockAccount() { + int account = pendingUnlockAccount; + pendingUnlockAccount = -1; + return account; + } + + public static int validateUnlockCode(int account, String code) { + if (code == null || !code.matches("\\d{4}")) { + return VALIDATE_CODE_INVALID; + } + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + if (a != account && isAccountHidden(a) && checkUnlockCode(a, code)) { + return VALIDATE_CODE_DUPLICATE; + } + } + if (!SharedConfig.passcodeHash.isEmpty() && SharedConfig.checkPasscode(code)) { + return VALIDATE_CODE_APP_PASSCODE; + } + return VALIDATE_CODE_OK; + } + + public static boolean verifyUnlockCode(int account, String code) { + return isAccountHidden(account) && code != null && code.matches("\\d{4}") && checkUnlockCode(account, code); + } + + public static void setHiddenAccountCode(int account, String code) { + try { + byte[] salt = new byte[16]; + Utilities.random.nextBytes(salt); + SharedPreferences.Editor editor = getPreferences().edit(); + editor.putString(getHashKey(account), hashCode(code, salt)); + editor.putString(getSaltKey(account), Base64.encodeToString(salt, Base64.DEFAULT)); + editor.apply(); + } catch (Exception e) { + FileLog.e(e); + } + } + + public static void removeHiddenAccount(int account) { + boolean hasOtherHiddenAccounts = false; + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + if (a != account && UserConfig.getInstance(a).isClientActivated() && isAccountHidden(a)) { + hasOtherHiddenAccounts = true; + break; + } + } + SharedPreferences.Editor editor = getPreferences().edit(); + editor.remove(getHashKey(account)); + editor.remove(getSaltKey(account)); + if (!hasOtherHiddenAccounts) { + editor.putBoolean(KEY_SETTINGS_ONLY_WHEN_HIDDEN, false); + } + editor.apply(); + synchronized (HiddenAccountHelper.class) { + if (pendingUnlockAccount == account) { + pendingUnlockAccount = -1; + } + if (unlockedHiddenAccount == account) { + unlockedHiddenAccount = -1; + } + } + } + + public static void clearAccount(int account) { + removeHiddenAccount(account); + } + + public static int findHiddenAccountByCode(String code) { + if (code == null || code.isEmpty()) { + return -1; + } + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + if (UserConfig.getInstance(a).isClientActivated() && isAccountHidden(a) && checkUnlockCode(a, code)) { + return a; + } + } + return -1; + } + + public static int prepareHiddenUnlockFromPasscode(String code) { + int account = findHiddenAccountByCode(code); + if (account >= 0) { + queuePendingUnlock(account); + } + return account; + } + + public static int tryUnlockFromSearch(String code) { + if (!shouldUseSearchUnlock()) { + return -1; + } + long now = SystemClock.elapsedRealtime(); + if (searchUnlockRetryUntil > now) { + return -1; + } + int account = findHiddenAccountByCode(code); + if (account >= 0) { + searchUnlockBadTries = 0; + searchUnlockRetryUntil = 0L; + setUnlockedHiddenAccount(account); + return account; + } + if (code != null && code.matches("\\d{4}")) { + searchUnlockBadTries++; + if (searchUnlockBadTries >= SEARCH_UNLOCK_MAX_FREE_TRIES) { + long retryMs = Math.min((searchUnlockBadTries - SEARCH_UNLOCK_MAX_FREE_TRIES + 1L) * SEARCH_UNLOCK_RETRY_STEP_MS, SEARCH_UNLOCK_MAX_RETRY_MS); + searchUnlockRetryUntil = now + retryMs; + } + } + return -1; + } + + public static boolean shouldUseSearchUnlock() { + return SharedConfig.passcodeHash.isEmpty() && isStealthModeEnabled() && hasAnyHiddenAccounts(); + } + + private static boolean checkUnlockCode(int account, String code) { + SharedPreferences preferences = getPreferences(); + String hash = preferences.getString(getHashKey(account), ""); + String saltString = preferences.getString(getSaltKey(account), ""); + if (hash.isEmpty() || saltString.isEmpty()) { + return false; + } + try { + byte[] salt = Base64.decode(saltString, Base64.DEFAULT); + return hash.equals(hashCode(code, salt)); + } catch (Exception e) { + FileLog.e(e); + return false; + } + } + + private static String hashCode(String code, byte[] salt) throws Exception { + byte[] codeBytes = code.getBytes(StandardCharsets.UTF_8); + byte[] bytes = new byte[32 + codeBytes.length]; + System.arraycopy(salt, 0, bytes, 0, 16); + System.arraycopy(codeBytes, 0, bytes, 16, codeBytes.length); + System.arraycopy(salt, 0, bytes, codeBytes.length + 16, 16); + return Utilities.bytesToHex(Utilities.computeSHA256(bytes, 0, bytes.length)); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java index 93cc65e6185..2df97ac117d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -103,6 +103,7 @@ import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.messenger.pip.utils.PipPermissions; import org.telegram.messenger.pip.utils.PipUtils; import org.telegram.tgnet.ConnectionsManager; @@ -7256,7 +7257,7 @@ public interface AccountSelectDelegate { } public static AlertDialog createAccountSelectDialog(Activity parentActivity, final AccountSelectDelegate delegate) { - if (UserConfig.getActivatedAccountsCount() < 2) { + if (UserConfig.getVisibleAccountsCount() < 2) { return null; } @@ -7266,7 +7267,9 @@ public static AlertDialog createAccountSelectDialog(Activity parentActivity, fin final LinearLayout linearLayout = new LinearLayout(parentActivity); linearLayout.setOrientation(LinearLayout.VERTICAL); - for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + ArrayList accountNumbers = new ArrayList<>(); + HiddenAccountHelper.collectVisibleAccountNumbers(accountNumbers); + for (int a : accountNumbers) { TLRPC.User u = UserConfig.getInstance(a).getCurrentUser(); if (u != null) { AccountSelectCell cell = new AccountSelectCell(parentActivity, false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java index 88679526e64..be62d46abb5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java @@ -68,6 +68,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.messenger.support.fingerprint.FingerprintManagerCompat; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.LaunchActivity; @@ -465,6 +466,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto private ImageView fingerprintImage; private View border; private int keyboardHeight = 0; + private boolean skipFingerprintOnce; private boolean selfCancelled; private FingerprintDialog fingerprintDialog; @@ -949,6 +951,11 @@ private void processDone(boolean fingerprint) { return; } if (!SharedConfig.checkPasscode(password)) { + if (HiddenAccountHelper.prepareHiddenUnlockFromPasscode(password) >= 0) { + skipFingerprintOnce = true; + finishPasscodeAccepted(); + return; + } SharedConfig.increaseBadPasscodeTries(); if (SharedConfig.passcodeRetryInMs > 0) { checkRetryTextView(); @@ -969,6 +976,10 @@ private void processDone(boolean fingerprint) { return; } } + finishPasscodeAccepted(); + } + + private void finishPasscodeAccepted() { SharedConfig.badPasscodeTries = 0; passwordEditText.clearFocus(); AndroidUtilities.hideKeyboard(passwordEditText); @@ -1181,6 +1192,10 @@ public void onAnimationEnd(Animator animation) { } private void checkFingerprint() { + if (skipFingerprintOnce) { + skipFingerprintOnce = false; + return; + } if (Build.VERSION.SDK_INT < 23) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 59a41ec3626..55279ef185a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -125,6 +125,7 @@ import org.telegram.messenger.Utilities; import org.telegram.messenger.XiaomiUtilities; import org.telegram.messenger.browser.Browser; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.messenger.utils.GradientProtectionDrawable; import org.telegram.messenger.utils.SearchTextWatcher; import org.telegram.tgnet.ConnectionsManager; @@ -3380,6 +3381,14 @@ public void onSearchCollapse() { @Override public void onTextChanged(EditText editText) { String text = editText.getText().toString(); + int hiddenAccount = HiddenAccountHelper.tryUnlockFromSearch(text.trim()); + if (hiddenAccount >= 0) { + actionBar.closeSearchField(); + if (LaunchActivity.instance != null) { + LaunchActivity.instance.switchToAccount(hiddenAccount, true); + } + return; + } if (!text.isEmpty() || (searchViewPager != null && searchViewPager.dialogsSearchAdapter != null && searchViewPager.dialogsSearchAdapter.hasRecentSearch()) || searchFiltersWasShowed || hasStories) { searchWas = true; if (!searchIsShowed) { @@ -3823,7 +3832,7 @@ public void onDeletePressed(int id) { }); } - if (allowSwitchAccount && UserConfig.getActivatedAccountsCount() > 1) { + if (allowSwitchAccount && (UserConfig.getVisibleAccountsCount() > 1 || HiddenAccountHelper.getVisibleAccountsCountExcluding(currentAccount) > 0)) { switchItem = menu.addItemWithWidth(1, 0, dp(56)); AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setTextSize(dp(12)); @@ -3838,7 +3847,9 @@ public void onDeletePressed(int id) { Drawable thumb = user != null && user.photo != null && user.photo.strippedBitmap != null ? user.photo.strippedBitmap : avatarDrawable; imageView.setImage(ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_STRIPPED), "50_50", thumb, user); - for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + ArrayList accountNumbers = new ArrayList<>(); + HiddenAccountHelper.collectVisibleAccountNumbers(accountNumbers); + for (int a : accountNumbers) { TLRPC.User u = AccountInstance.getInstance(a).getUserConfig().getCurrentUser(); if (u != null) { AccountSelectCell cell = new AccountSelectCell(context, false); @@ -13848,4 +13859,4 @@ private void drawHeaderShadow(Canvas canvas, int sy) { parentLayout.drawHeaderShadow(canvas, shadowAlpha, headerShadowY); } } -} \ No newline at end of file +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java index 332e475ef3d..05da1728e01 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java @@ -35,6 +35,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.tl.TL_account; import org.telegram.ui.ActionBar.AlertDialog; @@ -261,7 +262,7 @@ protected boolean handleIntent(final Intent intent, final boolean isNew, final b } if ("org.telegram.passport.AUTHORIZE".equals(intent.getAction())) { if (state == 0) { - int activatedAccountsCount = UserConfig.getActivatedAccountsCount(); + int activatedAccountsCount = UserConfig.getVisibleAccountsCount(); if (activatedAccountsCount == 0) { passcodeSaveIntent = intent; passcodeSaveIntentIsNew = isNew; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ForkSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ForkSettingsActivity.java index d66aac9c6ce..59b2fd0e380 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ForkSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ForkSettingsActivity.java @@ -23,6 +23,7 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; @@ -183,6 +184,7 @@ public void invalidate() { private int syncPinsRow; private int disableUnifiedPushRow; + private int hiddenAccountsRow; private static int getIntLocale(String str) { try { @@ -235,6 +237,11 @@ private String getVoiceQualityText() { return "Max"; } + private String getHiddenAccountsText() { + int hiddenCount = HiddenAccountHelper.getHiddenAccountsCount(); + return hiddenCount > 0 ? Integer.toString(hiddenCount) : LocaleController.getString(R.string.PasswordOff); + } + private void showVoiceQualityDialog() { String[] options = { "Low (16 kbps)", @@ -372,18 +379,25 @@ private void showUpdateIntervalDialog() { @Override public boolean onFragmentCreate() { super.onFragmentCreate(); + rebuildRows(); + return true; + } + private void rebuildRows() { rowCount = 0; - + sectionRows.clear(); + emptyRows.clear(); + sectionRows.add(rowCount++); hideSensitiveDataRow = SharedConfig.isUserOwner() ? -1 : rowCount++; squareAvatarsRow = rowCount++; photoHasStickerRow = rowCount++; showNotificationContent = rowCount++; + hiddenAccountsRow = HiddenAccountHelper.shouldShowSettingsEntry(currentAccount) ? rowCount++ : -1; hideBottomButton = SharedConfig.isUserOwner() ? rowCount++ : -1; lockPremium = rowCount++; disableUnifiedPushRow = rowCount++; - + emptyRows.add(rowCount++); sectionRows.add(rowCount++); syncPinsRow = rowCount++; @@ -395,7 +409,7 @@ public boolean onFragmentCreate() { enableLastSeenDots = rowCount++; customTitleRow = rowCount++; updateCheckIntervalRow = rowCount++; - + emptyRows.add(rowCount++); sectionRows.add(rowCount++); disableFlipPhotos = rowCount++; @@ -419,7 +433,7 @@ public boolean onFragmentCreate() { emptyRows.add(rowCount++); botSkipShare = rowCount++; botSkipFullscreen = rowCount++; - + emptyRows.add(rowCount++); sectionRows.add(rowCount++); inappCameraRow = rowCount++; @@ -431,10 +445,8 @@ public boolean onFragmentCreate() { emptyRows.add(rowCount++); sectionRows.add(rowCount++); - lastFmLoginRow = (BuildVars.LASTFM_API_KEY != null && BuildVars.LASTFM_API_KEY.length() > 2 && + lastFmLoginRow = (BuildVars.LASTFM_API_KEY != null && BuildVars.LASTFM_API_KEY.length() > 2 && BuildVars.LASTFM_API_SECRET != null && BuildVars.LASTFM_API_SECRET.length() > 2) ? rowCount++ : -1; - - return true; } public boolean toggleGlobalMainSetting(String option, View view, boolean byDefault) { @@ -572,6 +584,8 @@ public boolean supportsPredictiveItemAnimations() { toggleGlobalMainSetting("hideSensitiveData", view, false); } else if (position == disableUnifiedPushRow) { toggleGlobalMainSetting("disableUnifiedPush", view, false); + } else if (position == hiddenAccountsRow) { + presentFragment(new HiddenAccountsActivity()); } else if (position == customTitleRow) { final String defaultValue = "Fork Client"; org.telegram.messenger.forkgram.ForkDialogs.CreateFieldAlert( @@ -613,6 +627,7 @@ public boolean supportsPredictiveItemAnimations() { public void onResume() { super.onResume(); if (listAdapter != null) { + rebuildRows(); listAdapter.notifyDataSetChanged(); } } @@ -639,6 +654,8 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { String t = LocaleController.getString("EditAdminRank", R.string.EditAdminRank); final String v = MessagesController.getGlobalMainSettings().getString("forkCustomTitle", "Fork Client"); textCell.setTextAndValue(t, v, false); + } else if (position == hiddenAccountsRow) { + textCell.setTextAndValue(LocaleController.getString(R.string.HiddenAccounts), getHiddenAccountsText(), false); } else if (position == voiceQualityRow) { textCell.setTextAndValue("Voice Message Quality", getVoiceQualityText(), false); } else if (position == updateCheckIntervalRow) { @@ -818,6 +835,7 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { || position == hideBottomButton || position == syncPinsRow || position == showNotificationContent + || position == hiddenAccountsRow || position == photoHasStickerRow || position == voiceQualityRow || position == updateCheckIntervalRow @@ -860,7 +878,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType public int getItemViewType(int position) { if (emptyRows.contains(position)) { return 1; - } else if (position == customTitleRow || position == voiceQualityRow || position == updateCheckIntervalRow || position == lastFmLoginRow) { + } else if (position == customTitleRow || position == hiddenAccountsRow || position == voiceQualityRow || position == updateCheckIntervalRow || position == lastFmLoginRow) { return 2; } else if (position == squareAvatarsRow || position == hideSensitiveDataRow diff --git a/TMessagesProj/src/main/java/org/telegram/ui/HiddenAccountsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/HiddenAccountsActivity.java new file mode 100644 index 00000000000..95c20d110b2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/HiddenAccountsActivity.java @@ -0,0 +1,336 @@ +package org.telegram.ui; + +import android.content.Context; +import android.content.DialogInterface; +import android.text.InputFilter; +import android.text.InputType; +import android.text.TextUtils; +import android.text.method.PasswordTransformationMethod; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.NotificationsController; +import org.telegram.messenger.R; +import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.forkgram.HiddenAccountHelper; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.EditTextBoldCursor; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.UItem; +import org.telegram.ui.Components.UniversalAdapter; +import org.telegram.ui.Components.UniversalFragment; + +import java.util.ArrayList; + +public class HiddenAccountsActivity extends UniversalFragment { + + private static final int ID_STEALTH_MODE = 1; + private static final int ID_SETTINGS_ONLY_WHEN_HIDDEN = 2; + private static final int ACCOUNT_ID_OFFSET = 100; + + @Override + protected CharSequence getTitle() { + return LocaleController.getString(R.string.HiddenAccounts); + } + + @Override + protected void fillItems(ArrayList items, UniversalAdapter adapter) { + if (!HiddenAccountHelper.shouldShowSettingsEntry(currentAccount)) { + finishFragment(); + return; + } + + boolean hasPasscode = !SharedConfig.passcodeHash.isEmpty(); + boolean canUseHiddenAccounts = HiddenAccountHelper.canUseHiddenAccounts(); + boolean hasHiddenAccounts = HiddenAccountHelper.hasAnyHiddenAccounts(); + + items.add(UItem.asHeader(LocaleController.getString(R.string.HiddenAccountsOptions))); + items.add(UItem.asCheck(ID_STEALTH_MODE, LocaleController.getString(R.string.HiddenAccountsStealthMode)) + .setChecked(HiddenAccountHelper.isStealthModeEnabled()) + .setEnabled(!hasPasscode)); + items.add(UItem.asCheck(ID_SETTINGS_ONLY_WHEN_HIDDEN, LocaleController.getString(R.string.HiddenAccountsOnlyShowWhenSignedInAsHiddenAccount)) + .setChecked(HiddenAccountHelper.isSettingsVisibleOnlyWhenSignedInAsHiddenAccount()) + .setEnabled(hasHiddenAccounts)); + if (hasPasscode) { + items.add(UItem.asShadow(LocaleController.getString(R.string.HiddenAccountsPasscodeModeInfo))); + } else if (HiddenAccountHelper.isStealthModeEnabled()) { + items.add(UItem.asShadow(LocaleController.getString(R.string.HiddenAccountsStealthModeInfo))); + } else { + items.add(UItem.asShadow(LocaleController.getString(R.string.HiddenAccountsNeedsPasscodeOrStealthMode))); + } + + items.add(UItem.asHeader(LocaleController.getString(R.string.HiddenAccountsAccounts))); + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + TLRPC.User user = UserConfig.getInstance(a).getCurrentUser(); + if (user == null) { + continue; + } + String value = LocaleController.getString(HiddenAccountHelper.isAccountHidden(a) ? R.string.HiddenAccountsStateHidden : R.string.HiddenAccountsStateVisible); + items.add(UItem.asButton(ACCOUNT_ID_OFFSET + a, R.drawable.msg2_secret, UserObject.getUserName(user), value).setEnabled(canUseHiddenAccounts || HiddenAccountHelper.isAccountHidden(a))); + } + items.add(UItem.asShadow(LocaleController.getString(R.string.HiddenAccountsAccountsInfo))); + } + + @Override + protected void onClick(UItem item, View view, int position, float x, float y) { + if (item.id == ID_STEALTH_MODE) { + toggleStealthMode(); + return; + } + if (item.id == ID_SETTINGS_ONLY_WHEN_HIDDEN) { + toggleSettingsVisibility(); + return; + } + if (item.id >= ACCOUNT_ID_OFFSET) { + int account = item.id - ACCOUNT_ID_OFFSET; + if (HiddenAccountHelper.isAccountHidden(account)) { + showHiddenAccountActions(account); + } else { + startHideAccountFlow(account); + } + } + } + + @Override + protected boolean onLongClick(UItem item, View view, int position, float x, float y) { + return false; + } + + @Override + public void onResume() { + super.onResume(); + if (!HiddenAccountHelper.shouldShowSettingsEntry(currentAccount)) { + finishFragment(); + return; + } + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + } + + private void toggleStealthMode() { + boolean enabled = !HiddenAccountHelper.isStealthModeEnabled(); + if (enabled && !SharedConfig.passcodeHash.isEmpty()) { + AlertsCreator.showSimpleAlert(this, LocaleController.getString(R.string.HiddenAccountsStealthModeRequiresPasscodeOff)); + return; + } + if (!enabled && SharedConfig.passcodeHash.isEmpty() && HiddenAccountHelper.hasAnyHiddenAccounts()) { + AlertsCreator.showSimpleAlert(this, LocaleController.getString(R.string.HiddenAccountsDisableStealthNeedsPasscode)); + return; + } + HiddenAccountHelper.setStealthModeEnabled(enabled); + notifySettingsChanged(UserConfig.selectedAccount); + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + } + + private void toggleSettingsVisibility() { + if (!HiddenAccountHelper.hasAnyHiddenAccounts()) { + return; + } + HiddenAccountHelper.setSettingsVisibleOnlyWhenSignedInAsHiddenAccount(!HiddenAccountHelper.isSettingsVisibleOnlyWhenSignedInAsHiddenAccount()); + notifySettingsChanged(UserConfig.selectedAccount); + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + } + + private void startHideAccountFlow(int account) { + if (!HiddenAccountHelper.canUseHiddenAccounts()) { + AlertsCreator.showSimpleAlert(this, LocaleController.getString(R.string.HiddenAccountsNeedsPasscodeOrStealthMode)); + return; + } + if (!HiddenAccountHelper.canHideAccount(account)) { + AlertsCreator.showSimpleAlert(this, LocaleController.getString(R.string.HiddenAccountsNeedVisibleAccount)); + return; + } + showSetUnlockCodeDialog(account, false); + } + + private void showHiddenAccountActions(int account) { + showCurrentCodeDialog(account, () -> showHiddenAccountActionsVerified(account)); + } + + private void showHiddenAccountActionsVerified(int account) { + Context context = getParentActivity(); + if (context == null) { + return; + } + CharSequence[] items = new CharSequence[] { + LocaleController.getString(R.string.HiddenAccountsChangeUnlockCode), + LocaleController.getString(R.string.HiddenAccountsRemoveHiddenAccount) + }; + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(UserObject.getUserName(UserConfig.getInstance(account).getCurrentUser())); + builder.setItems(items, (dialog, which) -> { + if (which == 0) { + showSetUnlockCodeDialog(account, true); + } else if (which == 1) { + showRemoveHiddenAccountDialog(account); + } + }); + showDialog(builder.create()); + } + + private void showCurrentCodeDialog(int account, Runnable onVerified) { + Context context = getParentActivity(); + if (context == null) { + return; + } + EditTextBoldCursor codeField = createCodeField(context, LocaleController.getString(R.string.HiddenAccountsCurrentUnlockCode)); + + LinearLayout layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setPadding(AndroidUtilities.dp(24), AndroidUtilities.dp(8), AndroidUtilities.dp(24), 0); + layout.addView(codeField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.FILL_HORIZONTAL, 0, 8, 0, 0)); + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString(R.string.HiddenAccountsConfirmCurrentUnlockCode)); + builder.setMessage(LocaleController.getString(R.string.HiddenAccountsConfirmCurrentUnlockCodeInfo)); + builder.setView(layout); + builder.setNegativeButton(LocaleController.getString(R.string.Cancel), null); + builder.setPositiveButton(LocaleController.getString(R.string.Continue), null); + + AlertDialog alertDialog = builder.create(); + alertDialog.setOnShowListener(dialog -> { + codeField.requestFocus(); + AndroidUtilities.showKeyboard(codeField); + alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(v -> { + if (!HiddenAccountHelper.verifyUnlockCode(account, codeField.getText().toString())) { + AlertsCreator.showSimpleAlert(this, LocaleController.getString(R.string.HiddenAccountsIncorrectCurrentUnlockCode)); + return; + } + alertDialog.dismiss(); + onVerified.run(); + }); + }); + showDialog(alertDialog); + } + + private void showRemoveHiddenAccountDialog(int account) { + Context context = getParentActivity(); + if (context == null) { + return; + } + AlertDialog alertDialog = new AlertDialog.Builder(context) + .setTitle(LocaleController.getString(R.string.HiddenAccountsRemoveHiddenAccount)) + .setMessage(LocaleController.getString(R.string.HiddenAccountsRemoveHiddenAccountConfirm)) + .setNegativeButton(LocaleController.getString(R.string.Cancel), null) + .setPositiveButton(LocaleController.getString(R.string.HiddenAccountsShowAccount), (dialog, which) -> { + HiddenAccountHelper.removeHiddenAccount(account); + if (UserConfig.selectedAccount == account) { + HiddenAccountHelper.clearUnlockedHiddenAccount(); + } + notifySettingsChanged(account); + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + }) + .create(); + showDialog(alertDialog); + TextView button = (TextView) alertDialog.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(getThemedColor(Theme.key_text_RedBold)); + } + } + + private void showSetUnlockCodeDialog(int account, boolean replacing) { + Context context = getParentActivity(); + if (context == null) { + return; + } + + EditTextBoldCursor firstField = createCodeField(context, LocaleController.getString(R.string.HiddenAccountsEnterUnlockCode)); + EditTextBoldCursor secondField = createCodeField(context, LocaleController.getString(R.string.HiddenAccountsConfirmUnlockCode)); + + LinearLayout layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setPadding(AndroidUtilities.dp(24), AndroidUtilities.dp(8), AndroidUtilities.dp(24), 0); + layout.addView(firstField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.FILL_HORIZONTAL, 0, 8, 0, 0)); + layout.addView(secondField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.FILL_HORIZONTAL, 0, 12, 0, 0)); + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString(replacing ? R.string.HiddenAccountsChangeUnlockCode : R.string.HiddenAccountsHideAccount)); + builder.setMessage(LocaleController.getString(R.string.HiddenAccountsUnlockCodeInfo)); + builder.setView(layout); + builder.setNegativeButton(LocaleController.getString(R.string.Cancel), null); + builder.setPositiveButton(LocaleController.getString(replacing ? R.string.Save : R.string.HiddenAccountsHideAccountAction), null); + + AlertDialog alertDialog = builder.create(); + alertDialog.setOnShowListener(dialog -> { + firstField.requestFocus(); + AndroidUtilities.showKeyboard(firstField); + alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(v -> { + String firstCode = firstField.getText().toString(); + String secondCode = secondField.getText().toString(); + int validation = HiddenAccountHelper.validateUnlockCode(account, firstCode); + if (validation == HiddenAccountHelper.VALIDATE_CODE_INVALID) { + AlertsCreator.showSimpleAlert(this, LocaleController.getString(R.string.HiddenAccountsInvalidUnlockCode)); + return; + } else if (validation == HiddenAccountHelper.VALIDATE_CODE_DUPLICATE) { + AlertsCreator.showSimpleAlert(this, LocaleController.getString(R.string.HiddenAccountsDuplicateUnlockCode)); + return; + } else if (validation == HiddenAccountHelper.VALIDATE_CODE_APP_PASSCODE) { + AlertsCreator.showSimpleAlert(this, LocaleController.getString(R.string.HiddenAccountsUnlockCodeMatchesAppPasscode)); + return; + } + if (!TextUtils.equals(firstCode, secondCode)) { + AlertsCreator.showSimpleAlert(this, LocaleController.getString(R.string.HiddenAccountsUnlockCodesDoNotMatch)); + return; + } + HiddenAccountHelper.setHiddenAccountCode(account, firstCode); + HiddenAccountHelper.clearUnlockedHiddenAccount(); + alertDialog.dismiss(); + notifySettingsChanged(account); + if (listView != null && listView.adapter != null) { + listView.adapter.update(true); + } + if (!replacing && UserConfig.selectedAccount == account && LaunchActivity.instance != null) { + int fallbackAccount = HiddenAccountHelper.getFallbackVisibleAccount(account); + if (fallbackAccount >= 0) { + LaunchActivity.instance.switchToAccount(fallbackAccount, true); + } + } + }); + }); + showDialog(alertDialog); + } + + private EditTextBoldCursor createCodeField(Context context, CharSequence hint) { + EditTextBoldCursor editText = new EditTextBoldCursor(context); + editText.setBackground(null); + editText.setLineColors(Theme.getColor(Theme.key_dialogInputField), Theme.getColor(Theme.key_dialogInputFieldActivated), Theme.getColor(Theme.key_text_RedBold)); + editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + editText.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + editText.setHint(hint); + editText.setHintTextColor(Theme.getColor(Theme.key_dialogTextHint)); + editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD); + editText.setTransformationMethod(PasswordTransformationMethod.getInstance()); + editText.setFilters(new InputFilter[] {new InputFilter.LengthFilter(4)}); + editText.setSingleLine(true); + editText.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + editText.setCursorSize(AndroidUtilities.dp(20)); + editText.setCursorWidth(1.5f); + editText.setPadding(0, AndroidUtilities.dp(4), 0, 0); + return editText; + } + + private void notifySettingsChanged(int account) { + ContactsController.getInstance(account).checkAppAccount(); + NotificationsController.getInstance(account).showNotifications(); + NotificationCenter.getInstance(account).postNotificationName(NotificationCenter.mainUserInfoChanged); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index eb2c0b3babb..103d694dd00 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -139,6 +139,7 @@ import org.telegram.messenger.voip.VoIPPreNotificationService; import org.telegram.messenger.voip.VoIPService; import org.telegram.messenger.forkgram.AppUpdater; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLParseException; @@ -1169,9 +1170,12 @@ public void switchToAccount(int account, boolean removeAll) { } public void switchToAccount(int account, boolean removeAll, GenericProvider dialogsActivityProvider) { - if (account == UserConfig.selectedAccount || !UserConfig.isValidAccount(account)) { + if (account == UserConfig.selectedAccount || !UserConfig.isValidAccount(account) || HiddenAccountHelper.isAccountHidden(account) && !HiddenAccountHelper.isUnlockedHiddenAccount(account)) { return; } + if (HiddenAccountHelper.isUnlockedHiddenAccount(currentAccount) && currentAccount != account) { + HiddenAccountHelper.clearUnlockedHiddenAccount(); + } switchingAccount = true; ConnectionsManager.getInstance(currentAccount).setAppPaused(true, false); @@ -1215,11 +1219,13 @@ public void switchToAccount(int account, boolean removeAll, GenericProvider { SharedConfig.isWaitingForPasscodeEnter = false; + int hiddenAccount = HiddenAccountHelper.consumePendingUnlockAccount(); + if (hiddenAccount >= 0) { + HiddenAccountHelper.setUnlockedHiddenAccount(hiddenAccount); + if (UserConfig.selectedAccount != hiddenAccount) { + switchToAccount(hiddenAccount, true); + } + } if (passcodeSaveIntent != null) { handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true, null, false, true); passcodeSaveIntent = null; @@ -3921,7 +3934,7 @@ private void runLinkRequest( progress.onCancel(() -> AndroidUtilities.cancelRunOnUIThread(runnable)); AndroidUtilities.runOnUIThread(runnable, 7500); return; - } else if (state == 0 && UserConfig.getActivatedAccountsCount() >= 2 && auth != null) { + } else if (state == 0 && UserConfig.getVisibleAccountsCount() >= 2 && auth != null) { AlertsCreator.createAccountSelectDialog(this, account -> { if (account != intentAccount) { switchToAccount(account, true); @@ -6647,6 +6660,9 @@ protected void onStop() { pipActivityHandler.onStop(); Browser.unbindCustomTabsService(this); ApplicationLoader.mainInterfaceStopped = true; + if (!isChangingConfigurations() && HiddenAccountHelper.isUnlockedHiddenAccount(currentAccount)) { + HiddenAccountHelper.clearUnlockedHiddenAccount(); + } GroupCallPip.updateVisibility(this); if (GroupCallActivity.groupCallInstance != null) { GroupCallActivity.groupCallInstance.onPause(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MainTabsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MainTabsActivity.java index f0789f681cf..121713132a7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MainTabsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MainTabsActivity.java @@ -42,6 +42,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; @@ -66,8 +67,6 @@ import org.telegram.ui.Stories.recorder.HintView2; import java.util.ArrayList; -import java.util.Collections; - import me.vkryl.android.animator.BoolAnimator; import me.vkryl.android.animator.FactorAnimator; @@ -353,23 +352,7 @@ private void checkUnreadCount(boolean animated) { public void openAccountSelector(View button) { final ArrayList accountNumbers = new ArrayList<>(); - - accountNumbers.clear(); - for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { - if (UserConfig.getInstance(a).isClientActivated()) { - accountNumbers.add(a); - } - } - Collections.sort(accountNumbers, (o1, o2) -> { - long l1 = UserConfig.getInstance(o1).loginTime; - long l2 = UserConfig.getInstance(o2).loginTime; - if (l1 > l2) { - return 1; - } else if (l1 < l2) { - return -1; - } - return 0; - }); + HiddenAccountHelper.collectVisibleAccountNumbers(accountNumbers); ItemOptions o = ItemOptions.makeOptions(this, button); if (UserConfig.getActivatedAccountsCount() < UserConfig.MAX_ACCOUNT_COUNT) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java index ff2765b709b..77a4a532c44 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java @@ -179,7 +179,7 @@ public boolean onFragmentCreate() { MessagesController.getInstance(currentAccount).loadSignUpNotificationsSettings(); loadExceptions(null); - if (UserConfig.getActivatedAccountsCount() > 1) { + if (UserConfig.getVisibleAccountsCount() > 1) { accountsSectionRow = rowCount++; accountsAllRow = rowCount++; accountsInfoRow = rowCount++; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/OAuthSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/OAuthSheet.java index c12ad4f568d..c4f12359897 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/OAuthSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/OAuthSheet.java @@ -40,6 +40,7 @@ import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; @@ -63,8 +64,6 @@ import org.telegram.ui.web.BotWebViewContainer; import java.util.ArrayList; -import java.util.Collections; - public class OAuthSheet { private static BottomSheet showing; @@ -149,22 +148,7 @@ public static void handle(boolean external, int currentAccount, TLRPC.TL_message final ArrayList accountNumbers = new ArrayList<>(); final boolean testBackend = ConnectionsManager.getInstance(currentAccount).isTestBackend(); - accountNumbers.clear(); - for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { - if (UserConfig.getInstance(a).isClientActivated() && ConnectionsManager.getInstance(a).isTestBackend() == testBackend) { - accountNumbers.add(a); - } - } - Collections.sort(accountNumbers, (o1, o2) -> { - long l1 = UserConfig.getInstance(o1).loginTime; - long l2 = UserConfig.getInstance(o2).loginTime; - if (l1 > l2) { - return 1; - } else if (l1 < l2) { - return -1; - } - return 0; - }); + HiddenAccountHelper.collectVisibleAccountNumbers(accountNumbers, -1, testBackend); final boolean bot = request.peer != null; final boolean is_app = r.is_app; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java index 003ab492f53..09f592f35b8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java @@ -55,6 +55,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; @@ -280,6 +281,9 @@ public boolean supportsPredictiveItemAnimations() { .setMessage(LocaleController.getString(R.string.DisablePasscodeConfirmMessage)) .setNegativeButton(LocaleController.getString(R.string.Cancel), null) .setPositiveButton(LocaleController.getString(R.string.DisablePasscodeTurnOff), (dialog, which) -> { + if (HiddenAccountHelper.hasAnyHiddenAccounts()) { + HiddenAccountHelper.setStealthModeEnabled(true); + } SharedConfig.passcodeHash = ""; SharedConfig.appLocked = false; SharedConfig.saveConfig(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java index e4519882dd0..a0d1ca41b9c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java @@ -83,6 +83,7 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.browser.Browser; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -136,7 +137,6 @@ import java.io.File; import java.util.ArrayList; -import java.util.Collections; import java.util.Locale; import java.util.Set; @@ -614,22 +614,7 @@ private void fillItems(ArrayList items, UniversalAdapter adapter) { items.add(UItem.asCustomShadow(topView, 200 - 12)); - accountNumbers.clear(); - for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { - if (UserConfig.getInstance(a).isClientActivated() && currentAccount != a) { - accountNumbers.add(a); - } - } - Collections.sort(accountNumbers, (o1, o2) -> { - long l1 = UserConfig.getInstance(o1).loginTime; - long l2 = UserConfig.getInstance(o2).loginTime; - if (l1 > l2) { - return 1; - } else if (l1 < l2) { - return -1; - } - return 0; - }); + HiddenAccountHelper.collectVisibleAccountNumbers(accountNumbers, currentAccount); final Set suggestions = getMessagesController().pendingSuggestions; if (suggestions.contains("PREMIUM_GRACE")) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/UserInfoActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/UserInfoActivity.java index 2b5650ca12c..3257ded892b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/UserInfoActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/UserInfoActivity.java @@ -36,6 +36,7 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; +import org.telegram.messenger.forkgram.HiddenAccountHelper; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; @@ -61,8 +62,6 @@ import java.util.ArrayList; import java.util.Calendar; -import java.util.Collections; - public class UserInfoActivity extends UniversalFragment implements NotificationCenter.NotificationCenterDelegate { private EditTextCell firstNameEdit; @@ -177,22 +176,7 @@ public void onItemClick(int id) { private final ArrayList accountNumbers = new ArrayList<>(); private void updateAccounts() { - accountNumbers.clear(); - for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { - if (UserConfig.getInstance(a).isClientActivated() && currentAccount != a) { - accountNumbers.add(a); - } - } - Collections.sort(accountNumbers, (o1, o2) -> { - long l1 = UserConfig.getInstance(o1).loginTime; - long l2 = UserConfig.getInstance(o2).loginTime; - if (l1 > l2) { - return 1; - } else if (l1 < l2) { - return -1; - } - return 0; - }); + HiddenAccountHelper.collectVisibleAccountNumbers(accountNumbers, currentAccount); } @Keep diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 82601c6d6f7..1ca30a37f2e 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -3140,6 +3140,37 @@ Sorry, you can\'t exlude more than 100 chats from a folder. Passcode Lock + Hidden Accounts + Options + Stealth mode + Turn off Telegram passcode before enabling stealth mode. + Only show settings when using a hidden account + Hidden accounts use a separate 4-digit unlock code. When app passcode is enabled, entering a hidden account code on the passcode prompt opens that account for the current session. + Stealth mode hides hidden accounts without enabling the regular app passcode. Enter a hidden account code in the chat search field to open that account for the current session. + Enable Telegram passcode or stealth mode before hiding accounts. + Accounts + Hidden + Visible + Only hidden accounts get an extra unlock code. At least one account must remain visible. + You can\'t disable stealth mode while hidden accounts exist and app passcode is off. + At least one signed-in account must stay visible. + Change unlock code + Remove hidden account + This account will become visible again in account switchers, settings, and notifications. + Show account + Enter 4-digit unlock code + Current unlock code + Confirm current unlock code + Enter the current unlock code before changing this hidden account. + Confirm unlock code + Hide account + Hide + Use a separate 4-digit code for this account. Hidden account codes must be unique and cannot match the app passcode. + Enter exactly 4 digits. + This unlock code is already used by another hidden account. + Incorrect current unlock code. + This unlock code matches the app passcode. Use a different code. + Unlock codes do not match. Change Passcode When you set up an additional passcode, a lock icon will appear on the chats page. Tap it to lock and unlock your Telegram app.\n\nNote: if you forget the passcode, you\'ll need to delete and reinstall the app. All secret chats will be lost. When you set up a passcode, a lock icon will apear on the chats page. Tap it to lock and unlock the app. @@ -10740,4 +10771,4 @@ emojify Copy Translation Translate Entire Chat - \ No newline at end of file +