/* * This is the source code of Telegram for Android v. 5.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-2018. */ package org.telegram.ui; import android.Manifest; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.StateListAnimator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.telephony.PhoneNumberUtils; //import android.telephony.TelephonyManager; import android.text.Editable; import android.text.InputType; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; import android.text.method.PasswordTransformationMethod; import android.text.style.ClickableSpan; import android.text.style.ReplacementSpan; import android.util.Base64; import android.util.TypedValue; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.view.inputmethod.EditorInfo; import android.widget.AdapterView; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.Space; import android.widget.TextView; import android.widget.ViewSwitcher; import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import org.telegram.PhoneFormat.PhoneFormat; 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.Emoji; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SRPHelper; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.AnimatedPhoneNumberEditText; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.CustomPhoneKeyboardView; import org.telegram.ui.Components.Easings; import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.ImageUpdater; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.OutlineTextContainerView; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.SimpleThemeDescription; import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.SlideView; import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.TextViewSwitcher; import org.telegram.ui.Components.TransformableLoginButtonView; import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.VerticalPositionAutoAnimator; import org.telegram.ui.Components.spoilers.SpoilersTextView; import java.io.BufferedReader; import java.io.InputStreamReader; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.atomic.AtomicReference; import tw.nekomimi.nekogram.NekoXConfig; import tw.nekomimi.nekogram.ui.EditTextAutoFill; import tw.nekomimi.nekogram.utils.AlertUtil; import tw.nekomimi.nekogram.utils.ProxyUtil; @SuppressLint("HardwareIds") public class LoginActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private final static int SHOW_DELAY = SharedConfig.getDevicePerformanceClass() <= SharedConfig.PERFORMANCE_CLASS_AVERAGE ? 150 : 100; public final static int AUTH_TYPE_MESSAGE = 1, AUTH_TYPE_SMS = 2, AUTH_TYPE_FLASH_CALL = 3, AUTH_TYPE_CALL = 4, AUTH_TYPE_MISSED_CALL = 11; private final static int VIEW_PHONE_INPUT = 0, VIEW_CODE_MESSAGE = 1, VIEW_CODE_SMS = 2, VIEW_CODE_FLASH_CALL = 3, VIEW_CODE_CALL = 4, VIEW_REGISTER = 5, VIEW_PASSWORD = 6, VIEW_RECOVER = 7, VIEW_RESET_WAIT = 8, VIEW_NEW_PASSWORD_STAGE_1 = 9, VIEW_NEW_PASSWORD_STAGE_2 = 10, VIEW_CODE_MISSED_CALL = 11; private final static int COUNTRY_STATE_NOT_SET_OR_VALID = 0, COUNTRY_STATE_EMPTY = 1, COUNTRY_STATE_INVALID = 2; @Retention(RetentionPolicy.SOURCE) @IntDef({ AUTH_TYPE_MESSAGE, AUTH_TYPE_SMS, AUTH_TYPE_FLASH_CALL, AUTH_TYPE_CALL, AUTH_TYPE_MISSED_CALL }) public @interface AuthType {} @Retention(RetentionPolicy.SOURCE) @IntDef({ VIEW_PHONE_INPUT, VIEW_CODE_MESSAGE, VIEW_CODE_SMS, VIEW_CODE_FLASH_CALL, VIEW_CODE_CALL, VIEW_REGISTER, VIEW_PASSWORD, VIEW_RECOVER, VIEW_RESET_WAIT, VIEW_NEW_PASSWORD_STAGE_1, VIEW_NEW_PASSWORD_STAGE_2, VIEW_CODE_MISSED_CALL }) private @interface ViewNumber {} @IntDef({ COUNTRY_STATE_NOT_SET_OR_VALID, COUNTRY_STATE_EMPTY, COUNTRY_STATE_INVALID }) private @interface CountryState {} @ViewNumber private int currentViewNum; private SlideView[] views = new SlideView[12]; private CustomPhoneKeyboardView keyboardView; private boolean restoringState; private Dialog permissionsDialog; private Dialog permissionsShowDialog; private ArrayList permissionsItems = new ArrayList<>(); private ArrayList permissionsShowItems = new ArrayList<>(); private boolean checkPermissions = true; private boolean checkShowPermissions = true; private boolean newAccount; private boolean syncContacts = false; private boolean testBackend = false; private boolean cancelAccountDeletionMode = false; private String cancelDeletionPhone; private Bundle cancelDeletionParams; private TLRPC.TL_auth_sentCode cancelDeletionCode; private int currentDoneType; private AnimatorSet[] showDoneAnimation = new AnimatorSet[2]; private AnimatorSet doneItemAnimation; private TransformableLoginButtonView floatingButtonIcon; private FrameLayout floatingButtonContainer; private VerticalPositionAutoAnimator floatingAutoAnimator; private RadialProgressView floatingProgressView; private int progressRequestId; private boolean[] doneButtonVisible = new boolean[]{true, false}; private AlertDialog cancelDeleteProgressDialog; private SizeNotifierFrameLayout sizeNotifierFrameLayout; private Runnable keyboardHideCallback; private ImageView backButtonView; private RadialProgressView radialProgressView; // Open animation stuff private LinearLayout keyboardLinearLayout; private FrameLayout slideViewsContainer; private View introView; private TextView startMessagingButton; private boolean customKeyboardWasVisible = false; private boolean isAnimatingIntro; private Runnable animationFinishCallback; private PhoneNumberConfirmView phoneNumberConfirmView; private static final int DONE_TYPE_FLOATING = 0; private static final int DONE_TYPE_ACTION = 1; private final static int done_button = 1; private boolean needRequestPermissions; private boolean[] doneProgressVisible = new boolean[2]; private Runnable[] editDoneCallback = new Runnable[2]; private boolean[] postedEditDoneCallback = new boolean[2]; private static Map phoneNumberExclusionRules = new HashMap<>(); // NekoX Definitions ActionBarMenuItem menu = null; private static final int menu_proxy = 2; private static final int menu_language = 3; private static final int menu_bot_login = 4; private static final int menu_other = 5; //private int menu_custom_api = 6; // private int menu_custom_dc = 7; private static final int menu_qr_login = 8; TLRPC.TL_auth_exportLoginToken exportLoginTokenRequest = null; AlertDialog exportLoginTokenProgress = null; android.app.AlertDialog exportLoginTokenDialog = null; static { phoneNumberExclusionRules.put("60", hintLengthFrom -> --hintLengthFrom); phoneNumberExclusionRules.put("372", hintLengthFrom -> --hintLengthFrom); } private static class ProgressView extends View { private final Path path = new Path(); private final RectF rect = new RectF(); private final RectF boundsRect = new RectF(); private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG); private long startTime; private long duration; private boolean animating; private float radius; public ProgressView(Context context) { super(context); paint.setColor(Theme.getColor(Theme.key_login_progressInner)); paint2.setColor(Theme.getColor(Theme.key_login_progressOuter)); } public void startProgressAnimation(long duration) { this.animating = true; this.duration = duration; this.startTime = System.currentTimeMillis(); invalidate(); } public void resetProgressAnimation() { duration = 0; startTime = 0; animating = false; invalidate(); } public boolean isProgressAnimationRunning() { return animating; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { path.rewind(); radius = h / 2f; boundsRect.set(0, 0, w, h); rect.set(boundsRect); path.addRoundRect(boundsRect, radius, radius, Path.Direction.CW); } @Override protected void onDraw(Canvas canvas) { final float progress; if (duration > 0) { progress = Math.min(1f, (System.currentTimeMillis() - startTime) / (float) duration); } else { progress = 0f; } canvas.clipPath(path); canvas.drawRoundRect(boundsRect, radius, radius, paint); rect.right = boundsRect.right * progress; canvas.drawRoundRect(rect, radius, radius, paint2); if (animating &= duration > 0 && progress < 1f) { postInvalidateOnAnimation(); } } } public LoginActivity() { super(); } public LoginActivity(int account) { super(); currentAccount = account; newAccount = true; } public LoginActivity cancelAccountDeletion(String phone, Bundle params, TLRPC.TL_auth_sentCode sentCode) { cancelDeletionPhone = phone; cancelDeletionParams = params; cancelDeletionCode = sentCode; cancelAccountDeletionMode = true; return this; } @Override public void onFragmentDestroy() { super.onFragmentDestroy(); for (int a = 0; a < views.length; a++) { if (views[a] != null) { views[a].onDestroyActivity(); } } if (cancelDeleteProgressDialog != null) { cancelDeleteProgressDialog.dismiss(); cancelDeleteProgressDialog = null; } for (Runnable callback : editDoneCallback) { if (callback != null) { AndroidUtilities.cancelRunOnUIThread(callback); } } SharedConfig.loginingAccount = -1; } @Override public View createView(Context context) { actionBar.setAddToContainer(false); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { if (id == done_button) { onDoneButtonPressed(); } else if (id == -1) { if (onBackPressed()) { finishFragment(); } } } }); currentDoneType = DONE_TYPE_FLOATING; doneButtonVisible[DONE_TYPE_FLOATING] = true; doneButtonVisible[DONE_TYPE_ACTION] = false; sizeNotifierFrameLayout = new SizeNotifierFrameLayout(context) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { MarginLayoutParams marginLayoutParams = (MarginLayoutParams) floatingButtonContainer.getLayoutParams(); int keyboardOffset = isCustomKeyboardVisible() ? AndroidUtilities.dp(CustomPhoneKeyboardView.KEYBOARD_HEIGHT_DP) : 0; if (isCustomKeyboardVisible() && measureKeyboardHeight() > AndroidUtilities.dp(20)) { keyboardOffset -= measureKeyboardHeight(); } if (Bulletin.getVisibleBulletin() != null && Bulletin.getVisibleBulletin().isShowing()) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); marginLayoutParams.bottomMargin = AndroidUtilities.dp(16) + Bulletin.getVisibleBulletin().getLayout().getMeasuredHeight() - AndroidUtilities.dp(10) + keyboardOffset; } else { marginLayoutParams.bottomMargin = AndroidUtilities.dp(16) + keyboardOffset; } int statusBarHeight = AndroidUtilities.isTablet() ? 0 : AndroidUtilities.statusBarHeight; marginLayoutParams = (MarginLayoutParams) backButtonView.getLayoutParams(); marginLayoutParams.topMargin = AndroidUtilities.dp(16) + statusBarHeight; marginLayoutParams = (MarginLayoutParams) radialProgressView.getLayoutParams(); marginLayoutParams.topMargin = AndroidUtilities.dp(16) + statusBarHeight; marginLayoutParams = (MarginLayoutParams) menu.getLayoutParams(); marginLayoutParams.topMargin = AndroidUtilities.dp(16) + statusBarHeight; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }; sizeNotifierFrameLayout.setDelegate((keyboardHeight, isWidthGreater) -> { if (keyboardHeight > AndroidUtilities.dp(20) && isCustomKeyboardVisible()) { AndroidUtilities.hideKeyboard(fragmentView); } if (keyboardHeight <= AndroidUtilities.dp(20) && keyboardHideCallback != null) { keyboardHideCallback.run(); keyboardHideCallback = null; } }); fragmentView = sizeNotifierFrameLayout; ScrollView scrollView = new ScrollView(context) { @Override public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { if (currentViewNum == VIEW_CODE_MESSAGE || currentViewNum == VIEW_CODE_SMS || currentViewNum == VIEW_CODE_CALL) { rectangle.bottom += AndroidUtilities.dp(40); } return super.requestChildRectangleOnScreen(child, rectangle, immediate); } }; scrollView.setFillViewport(true); sizeNotifierFrameLayout.addView(scrollView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); keyboardLinearLayout = new LinearLayout(context); keyboardLinearLayout.setOrientation(LinearLayout.VERTICAL); scrollView.addView(keyboardLinearLayout, LayoutHelper.createScroll(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT)); Space spacer = new Space(context); spacer.setMinimumHeight(AndroidUtilities.isTablet() ? 0 : AndroidUtilities.statusBarHeight); keyboardLinearLayout.addView(spacer); slideViewsContainer = new FrameLayout(context) { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); for (SlideView slideView : views) { MarginLayoutParams params = (MarginLayoutParams) slideView.getLayoutParams(); int childBottom = getHeight() + AndroidUtilities.dp(16); if (!slideView.hasCustomKeyboard() && keyboardView.getVisibility() == VISIBLE) { childBottom += AndroidUtilities.dp(CustomPhoneKeyboardView.KEYBOARD_HEIGHT_DP); } slideView.layout(params.leftMargin, params.topMargin, getWidth() - params.rightMargin, childBottom); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = getMeasuredWidth(), height = getMeasuredHeight(); for (SlideView slideView : views) { MarginLayoutParams params = (MarginLayoutParams) slideView.getLayoutParams(); int childHeight = height - params.topMargin + AndroidUtilities.dp(16); if (!slideView.hasCustomKeyboard() && keyboardView.getVisibility() == VISIBLE) { childHeight += AndroidUtilities.dp(CustomPhoneKeyboardView.KEYBOARD_HEIGHT_DP); } slideView.measure(MeasureSpec.makeMeasureSpec(width - params.rightMargin - params.leftMargin, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)); } } }; keyboardLinearLayout.addView(slideViewsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); keyboardView = new CustomPhoneKeyboardView(context); keyboardLinearLayout.addView(keyboardView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, CustomPhoneKeyboardView.KEYBOARD_HEIGHT_DP)); views[VIEW_PHONE_INPUT] = new PhoneView(context); views[VIEW_CODE_MESSAGE] = new LoginActivitySmsView(context, AUTH_TYPE_MESSAGE); views[VIEW_CODE_SMS] = new LoginActivitySmsView(context, AUTH_TYPE_SMS); views[VIEW_CODE_FLASH_CALL] = new LoginActivitySmsView(context, AUTH_TYPE_FLASH_CALL); views[VIEW_CODE_CALL] = new LoginActivitySmsView(context, AUTH_TYPE_CALL); views[VIEW_REGISTER] = new LoginActivityRegisterView(context); views[VIEW_PASSWORD] = new LoginActivityPasswordView(context); views[VIEW_RECOVER] = new LoginActivityRecoverView(context); views[VIEW_RESET_WAIT] = new LoginActivityResetWaitView(context); views[VIEW_NEW_PASSWORD_STAGE_1] = new LoginActivityNewPasswordView(context, 0); views[VIEW_NEW_PASSWORD_STAGE_2] = new LoginActivityNewPasswordView(context, 1); views[VIEW_CODE_MISSED_CALL] = new LoginActivitySmsView(context, AUTH_TYPE_MISSED_CALL); for (int a = 0; a < views.length; a++) { views[a].setVisibility(a == 0 ? View.VISIBLE : View.GONE); slideViewsContainer.addView(views[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER, AndroidUtilities.isTablet() ? 26 : 18, 30, AndroidUtilities.isTablet() ? 26 : 18, 0)); } Bundle savedInstanceState = loadCurrentState(newAccount); if (savedInstanceState != null) { currentViewNum = savedInstanceState.getInt("currentViewNum", 0); syncContacts = savedInstanceState.getInt("syncContacts", 0) == 1; if (currentViewNum >= VIEW_CODE_MESSAGE && currentViewNum <= VIEW_CODE_CALL) { int time = savedInstanceState.getInt("open"); if (time != 0 && Math.abs(System.currentTimeMillis() / 1000 - time) >= 24 * 60 * 60) { currentViewNum = VIEW_PHONE_INPUT; savedInstanceState = null; clearCurrentState(); } } else if (currentViewNum == VIEW_PASSWORD) { LoginActivityPasswordView view = (LoginActivityPasswordView) views[VIEW_PASSWORD]; if (view.currentPassword == null) { currentViewNum = VIEW_PHONE_INPUT; savedInstanceState = null; clearCurrentState(); } } else if (currentViewNum == VIEW_RECOVER) { LoginActivityRecoverView view = (LoginActivityRecoverView) views[VIEW_RECOVER]; if (view.passwordString == null) { currentViewNum = VIEW_PHONE_INPUT; savedInstanceState = null; clearCurrentState(); } } } floatingButtonContainer = new FrameLayout(context); floatingButtonContainer.setVisibility(doneButtonVisible[DONE_TYPE_FLOATING] ? View.VISIBLE : View.GONE); if (Build.VERSION.SDK_INT >= 21) { StateListAnimator animator = new StateListAnimator(); animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButtonIcon, "translationZ", AndroidUtilities.dp(2), AndroidUtilities.dp(4)).setDuration(200)); animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButtonIcon, "translationZ", AndroidUtilities.dp(4), AndroidUtilities.dp(2)).setDuration(200)); floatingButtonContainer.setStateListAnimator(animator); floatingButtonContainer.setOutlineProvider(new ViewOutlineProvider() { @SuppressLint("NewApi") @Override public void getOutline(View view, Outline outline) { outline.setOval(0, 0, AndroidUtilities.dp(56), AndroidUtilities.dp(56)); } }); } floatingAutoAnimator = VerticalPositionAutoAnimator.attach(floatingButtonContainer); sizeNotifierFrameLayout.addView(floatingButtonContainer, LayoutHelper.createFrame(Build.VERSION.SDK_INT >= 21 ? 56 : 60, Build.VERSION.SDK_INT >= 21 ? 56 : 60, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 24, 16)); floatingButtonContainer.setOnClickListener(view -> onDoneButtonPressed()); floatingAutoAnimator.addUpdateListener((animation, value, velocity) -> { if (phoneNumberConfirmView != null) { phoneNumberConfirmView.updateFabPosition(); } }); backButtonView = new ImageView(context); backButtonView.setImageResource(R.drawable.ic_ab_back); backButtonView.setOnClickListener(v -> { if (onBackPressed()) { finishFragment(); } }); backButtonView.setContentDescription(LocaleController.getString(R.string.Back)); int padding = AndroidUtilities.dp(4); backButtonView.setPadding(padding, padding, padding, padding); sizeNotifierFrameLayout.addView(backButtonView, LayoutHelper.createFrame(32, 32, Gravity.LEFT | Gravity.TOP, 16, 16, 0, 0)); menu = new ActionBarMenuItem(context, null, 0, Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); menu.setIcon(R.drawable.ic_ab_other); menu.setSubMenuOpenSide(1); menu.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector))); menu.addSubItem(menu_proxy, R.drawable.proxy_on, LocaleController.getString("Proxy", R.string.Proxy)); menu.addSubItem(menu_language, R.drawable.ic_translate, LocaleController.getString("Language", R.string.Language)); menu.addSubItem(menu_bot_login, R.drawable.list_bot, LocaleController.getString("BotLogin", R.string.BotLogin)); menu.addSubItem(menu_qr_login, R.drawable.wallet_qr, LocaleController.getString("ImportLogin", R.string.ImportLogin)); // otherItem.addSubItem(menu_custom_api, R.drawable.baseline_vpn_key_24, LocaleController.getString("CustomApi", R.string.CustomApi)); // menu.addSubItem(menu_custom_dc, R.drawable.baseline_sync_24, LocaleController.getString("CustomBackend", R.string.CustomBackend)); menu.setOnClickListener(v -> { menu.toggleSubMenu(); }); menu.setDelegate((id) -> { if (id == menu_proxy){ presentFragment(new ProxyListActivity()); } else if (id == menu_language) { presentFragment(new LanguageSelectActivity()); } else if (id == menu_bot_login) { doBotLogin(context); } else if (id == menu_qr_login) { getConnectionsManager().cleanup(false); regenerateLoginToken(false); } }); menu.setContentDescription(LocaleController.getString(R.string.items_other)); padding = AndroidUtilities.dp(4); menu.setPadding(padding, padding, padding, padding); sizeNotifierFrameLayout.addView(menu, LayoutHelper.createFrame(32, 32, Gravity.RIGHT | Gravity.TOP, 0, 16, 16, 0)); radialProgressView = new RadialProgressView(context); radialProgressView.setSize(AndroidUtilities.dp(20)); radialProgressView.setAlpha(0); radialProgressView.setScaleX(0.1f); radialProgressView.setScaleY(0.1f); sizeNotifierFrameLayout.addView(radialProgressView, LayoutHelper.createFrame(32, 32, Gravity.RIGHT | Gravity.TOP, 0, 16, 16, 0)); floatingButtonIcon = new TransformableLoginButtonView(context); floatingButtonIcon.setTransformType(TransformableLoginButtonView.TRANSFORM_OPEN_ARROW); floatingButtonIcon.setProgress(1f); floatingButtonIcon.setDrawBackground(false); floatingButtonContainer.setContentDescription(LocaleController.getString("Done", R.string.Done)); floatingButtonContainer.addView(floatingButtonIcon, LayoutHelper.createFrame(Build.VERSION.SDK_INT >= 21 ? 56 : 60, Build.VERSION.SDK_INT >= 21 ? 56 : 60)); floatingProgressView = new RadialProgressView(context); floatingProgressView.setSize(AndroidUtilities.dp(22)); floatingProgressView.setAlpha(0.0f); floatingProgressView.setScaleX(0.1f); floatingProgressView.setScaleY(0.1f); floatingProgressView.setVisibility(View.INVISIBLE); floatingButtonContainer.addView(floatingProgressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); if (savedInstanceState != null) { restoringState = true; } for (int a = 0; a < views.length; a++) { SlideView v = views[a]; if (savedInstanceState != null) { if (a >= VIEW_CODE_MESSAGE && a <= VIEW_CODE_CALL) { if (a == currentViewNum) { v.restoreStateParams(savedInstanceState); } } else { v.restoreStateParams(savedInstanceState); } } if (currentViewNum == a) { backButtonView.setVisibility(v.needBackButton() || newAccount ? View.VISIBLE : View.GONE); v.setVisibility(View.VISIBLE); v.onShow(); setCustomKeyboardVisible(v.hasCustomKeyboard(), false); currentDoneType = DONE_TYPE_FLOATING; boolean needFloatingButton = a == VIEW_PHONE_INPUT || a == VIEW_REGISTER || a == VIEW_PASSWORD || a == VIEW_NEW_PASSWORD_STAGE_1 || a == VIEW_NEW_PASSWORD_STAGE_2; showDoneButton(needFloatingButton, false); if (a == VIEW_CODE_MESSAGE || a == VIEW_CODE_SMS || a == VIEW_CODE_FLASH_CALL || a == VIEW_CODE_CALL) { currentDoneType = DONE_TYPE_ACTION; } } else { if (v.getVisibility() != View.GONE) { v.setVisibility(View.GONE); v.onHide(); } } } restoringState = false; updateColors(); if (cancelAccountDeletionMode) { fillNextCodeParams(cancelDeletionParams, cancelDeletionCode, false); } return fragmentView; } private boolean isCustomKeyboardForceDisabled() { return AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y || AndroidUtilities.isTablet() || AndroidUtilities.isAccessibilityTouchExplorationEnabled(); } private boolean isCustomKeyboardVisible() { return views[currentViewNum].hasCustomKeyboard() && !isCustomKeyboardForceDisabled(); } private void setCustomKeyboardVisible(boolean visible, boolean animate) { if (customKeyboardWasVisible == visible && animate) return; customKeyboardWasVisible = visible; if (isCustomKeyboardForceDisabled()) { visible = false; } if (visible) { AndroidUtilities.hideKeyboard(fragmentView); AndroidUtilities.requestAltFocusable(getParentActivity(), classGuid); if (animate) { ValueAnimator anim = ValueAnimator.ofFloat(0, 1).setDuration(300); anim.setInterpolator(CubicBezierInterpolator.DEFAULT); anim.addUpdateListener(animation -> { float val = (float) animation.getAnimatedValue(); keyboardView.setAlpha(val); keyboardView.setTranslationY((1f - val) * AndroidUtilities.dp(CustomPhoneKeyboardView.KEYBOARD_HEIGHT_DP)); }); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { keyboardView.setVisibility(View.VISIBLE); } }); anim.start(); } else { keyboardView.setVisibility(View.VISIBLE); } } else { AndroidUtilities.removeAltFocusable(getParentActivity(), classGuid); if (animate) { ValueAnimator anim = ValueAnimator.ofFloat(1, 0).setDuration(300); anim.setInterpolator(Easings.easeInOutQuad); anim.addUpdateListener(animation -> { float val = (float) animation.getAnimatedValue(); keyboardView.setAlpha(val); keyboardView.setTranslationY((1f - val) * AndroidUtilities.dp(CustomPhoneKeyboardView.KEYBOARD_HEIGHT_DP)); }); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { keyboardView.setVisibility(View.GONE); } }); anim.start(); } else { keyboardView.setVisibility(View.GONE); } } } @Override public void onPause() { super.onPause(); if (newAccount) { ConnectionsManager.getInstance(currentAccount).setAppPaused(true, false); } AndroidUtilities.removeAltFocusable(getParentActivity(), classGuid); } @Override public void onResume() { super.onResume(); if (newAccount) { ConnectionsManager.getInstance(currentAccount).setAppPaused(false, false); } AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); fragmentView.requestLayout(); try { if (currentViewNum >= VIEW_CODE_MESSAGE && currentViewNum <= VIEW_CODE_CALL && views[currentViewNum] instanceof LoginActivitySmsView) { int time = ((LoginActivitySmsView) views[currentViewNum]).openTime; if (time != 0 && Math.abs(System.currentTimeMillis() / 1000 - time) >= 24 * 60 * 60) { views[currentViewNum].onBackPressed(true); setPage(VIEW_PHONE_INPUT, false, null, true); } } } catch (Exception e) { FileLog.e(e); } if (currentViewNum == VIEW_PHONE_INPUT && !needRequestPermissions) { SlideView view = views[currentViewNum]; if (view != null) { view.onShow(); } } if (isCustomKeyboardVisible()) { AndroidUtilities.hideKeyboard(fragmentView); AndroidUtilities.requestAltFocusable(getParentActivity(), classGuid); } } @Override public boolean hasForceLightStatusBar() { return true; } @Override public void onConfigurationChanged(Configuration newConfig) { setCustomKeyboardVisible(views[currentViewNum].hasCustomKeyboard(), false); if (phoneNumberConfirmView != null) { phoneNumberConfirmView.dismiss(); } } @Override public void onRequestPermissionsResultFragment(int requestCode, String[] permissions, int[] grantResults) { if (permissions.length == 0 || grantResults.length == 0) return; boolean granted = grantResults[0] == PackageManager.PERMISSION_GRANTED; if (requestCode == 6) { checkPermissions = false; if (currentViewNum == VIEW_PHONE_INPUT) { ((PhoneView)views[currentViewNum]).confirmedNumber = true; views[currentViewNum].onNextPressed(null); } } else if (requestCode == BasePermissionsActivity.REQUEST_CODE_CALLS) { checkShowPermissions = false; if (currentViewNum == VIEW_PHONE_INPUT) { ((PhoneView) views[currentViewNum]).fillNumber(); } } else if (requestCode == BasePermissionsActivity.REQUEST_CODE_OPEN_CAMERA) { if (granted) { LoginActivityRegisterView registerView = (LoginActivityRegisterView) views[VIEW_REGISTER]; registerView.imageUpdater.openCamera(); } } else if (requestCode == BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE_FOR_AVATAR) { if (granted) { LoginActivityRegisterView registerView = (LoginActivityRegisterView) views[VIEW_REGISTER]; registerView.post(() -> registerView.imageUpdater.openGallery()); } } } public static Bundle loadCurrentState(boolean newAccount) { if (newAccount) { return null; } try { Bundle bundle = new Bundle(); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo2", Context.MODE_PRIVATE); Map params = preferences.getAll(); for (Map.Entry entry : params.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); String[] args = key.split("_\\|_"); if (args.length == 1) { if (value instanceof String) { bundle.putString(key, (String) value); } else if (value instanceof Integer) { bundle.putInt(key, (Integer) value); } } else if (args.length == 2) { Bundle inner = bundle.getBundle(args[0]); if (inner == null) { inner = new Bundle(); bundle.putBundle(args[0], inner); } if (value instanceof String) { inner.putString(args[1], (String) value); } else if (value instanceof Integer) { inner.putInt(args[1], (Integer) value); } } } return bundle; } catch (Exception e) { FileLog.e(e); } return null; } private void clearCurrentState() { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo2", Context.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); editor.clear(); editor.commit(); } private void putBundleToEditor(Bundle bundle, SharedPreferences.Editor editor, String prefix) { Set keys = bundle.keySet(); for (String key : keys) { Object obj = bundle.get(key); if (obj instanceof String) { if (prefix != null) { editor.putString(prefix + "_|_" + key, (String) obj); } else { editor.putString(key, (String) obj); } } else if (obj instanceof Integer) { if (prefix != null) { editor.putInt(prefix + "_|_" + key, (Integer) obj); } else { editor.putInt(key, (Integer) obj); } } else if (obj instanceof Bundle) { putBundleToEditor((Bundle) obj, editor, key); } } } @Override protected void onDialogDismiss(Dialog dialog) { if (Build.VERSION.SDK_INT >= 23) { if (dialog == permissionsDialog && !permissionsItems.isEmpty() && getParentActivity() != null) { try { getParentActivity().requestPermissions(permissionsItems.toArray(new String[0]), 6); } catch (Exception ignore) { } } else if (dialog == permissionsShowDialog && !permissionsShowItems.isEmpty() && getParentActivity() != null) { AndroidUtilities.runOnUIThread(() -> needRequestPermissions = false, 200); try { getParentActivity().requestPermissions(permissionsShowItems.toArray(new String[0]), 7); } catch (Exception ignore) { } } } } @Override public boolean onBackPressed() { if (currentViewNum == VIEW_PHONE_INPUT) { for (int a = 0; a < views.length; a++) { if (views[a] != null) { views[a].onDestroyActivity(); } } clearCurrentState(); return true; } else if (currentViewNum == VIEW_PASSWORD) { views[currentViewNum].onBackPressed(true); setPage(VIEW_PHONE_INPUT, true, null, true); } else if (currentViewNum == VIEW_RECOVER || currentViewNum == VIEW_RESET_WAIT) { views[currentViewNum].onBackPressed(true); setPage(VIEW_PASSWORD, true, null, true); } else if ((currentViewNum >= VIEW_CODE_MESSAGE && currentViewNum <= VIEW_CODE_CALL) || currentViewNum == AUTH_TYPE_MISSED_CALL) { if (views[currentViewNum].onBackPressed(false)) { setPage(VIEW_PHONE_INPUT, true, null, true); } } else if (currentViewNum == VIEW_REGISTER) { ((LoginActivityRegisterView) views[currentViewNum]).wrongNumber.callOnClick(); } else if (currentViewNum == VIEW_NEW_PASSWORD_STAGE_1) { views[currentViewNum].onBackPressed(true); setPage(VIEW_RECOVER, true, null, true); } else if (currentViewNum == VIEW_NEW_PASSWORD_STAGE_2) { views[currentViewNum].onBackPressed(true); setPage(VIEW_NEW_PASSWORD_STAGE_1, true, null, true); } return false; } @Override public void onActivityResultFragment(int requestCode, int resultCode, Intent data) { LoginActivityRegisterView registerView = (LoginActivityRegisterView) views[VIEW_REGISTER]; if (registerView != null) { registerView.imageUpdater.onActivityResult(requestCode, resultCode, data); } } private void needShowAlert(String title, String text) { if (text == null || getParentActivity() == null) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(title); builder.setMessage(text); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); showDialog(builder.create()); } private void onFieldError(View view, boolean allowErrorSelection) { view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); AndroidUtilities.shakeViewSpring(view, 3.5f); if (allowErrorSelection) { if (view instanceof OutlineTextContainerView) { Runnable callback = (Runnable) view.getTag(R.id.timeout_callback); if (callback != null) { view.removeCallbacks(callback); } OutlineTextContainerView outlineTextContainerView = (OutlineTextContainerView) view; AtomicReference timeoutCallbackRef = new AtomicReference<>(); // We can't use timeoutCallback before declaration otherwise EditText editText = outlineTextContainerView.getAttachedEditText(); TextWatcher textWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { editText.post(()-> { editText.removeTextChangedListener(this); editText.removeCallbacks(timeoutCallbackRef.get()); timeoutCallbackRef.get().run(); }); } @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) {} }; outlineTextContainerView.animateError(1f); Runnable timeoutCallback = () -> { outlineTextContainerView.animateError(0f); view.setTag(R.id.timeout_callback, null); if (editText != null) { editText.post(()-> editText.removeTextChangedListener(textWatcher)); } }; timeoutCallbackRef.set(timeoutCallback); view.postDelayed(timeoutCallback, 2000); view.setTag(R.id.timeout_callback, timeoutCallback); if (editText != null) { editText.addTextChangedListener(textWatcher); } } } } public static void needShowInvalidAlert(BaseFragment fragment, final String phoneNumber, final boolean banned) { if (fragment == null || fragment.getParentActivity() == null) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity()); builder.setTitle(LocaleController.getString(R.string.RestorePasswordNoEmailTitle)); if (banned) { builder.setMessage(LocaleController.getString("BannedPhoneNumber", R.string.BannedPhoneNumber)); } else { builder.setMessage(LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); } builder.setNeutralButton(LocaleController.getString("BotHelp", R.string.BotHelp), (dialog, which) -> { try { PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); Intent mailer = new Intent(Intent.ACTION_SENDTO); mailer.setData(Uri.parse("mailto:")); mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{banned ? "recover@telegram.org" : "login@stel.com"}); if (banned) { mailer.putExtra(Intent.EXTRA_SUBJECT, "Banned phone number: " + phoneNumber); mailer.putExtra(Intent.EXTRA_TEXT, "I'm trying to use my mobile phone number: " + phoneNumber + "\nBut Telegram says it's banned. Please help.\n\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault()); } else { mailer.putExtra(Intent.EXTRA_SUBJECT, "Invalid phone number: " + phoneNumber); mailer.putExtra(Intent.EXTRA_TEXT, "I'm trying to use my mobile phone number: " + phoneNumber + "\nBut Telegram says it's invalid. Please help.\n\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault()); } fragment.getParentActivity().startActivity(Intent.createChooser(mailer, "Send email...")); } catch (Exception e) { AlertDialog.Builder builder2 = new AlertDialog.Builder(fragment.getParentActivity()); builder2.setTitle(LocaleController.getString(R.string.RestorePasswordNoEmailTitle)); builder2.setMessage(LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); builder2.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); fragment.showDialog(builder2.create()); } }); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); fragment.showDialog(builder.create()); } private void showDoneButton(boolean show, boolean animated) { boolean floating = currentDoneType == 0; if (doneButtonVisible[currentDoneType] == show) { return; } if (showDoneAnimation[currentDoneType] != null) { if (animated) { showDoneAnimation[currentDoneType].removeAllListeners(); } showDoneAnimation[currentDoneType].cancel(); } doneButtonVisible[currentDoneType] = show; if (animated) { showDoneAnimation[currentDoneType] = new AnimatorSet(); if (show) { if (floating) { if (floatingButtonContainer.getVisibility() != View.VISIBLE) { floatingAutoAnimator.setOffsetY(AndroidUtilities.dpf2(70f)); floatingButtonContainer.setVisibility(View.VISIBLE); } ValueAnimator offsetAnimator = ValueAnimator.ofFloat(floatingAutoAnimator.getOffsetY(), 0); offsetAnimator.addUpdateListener(animation -> { float val = (Float) animation.getAnimatedValue(); floatingAutoAnimator.setOffsetY(val); floatingButtonContainer.setAlpha(1f - (val / AndroidUtilities.dpf2(70f))); }); showDoneAnimation[currentDoneType].play(offsetAnimator); } } else { if (floating) { ValueAnimator offsetAnimator = ValueAnimator.ofFloat(floatingAutoAnimator.getOffsetY(), AndroidUtilities.dpf2(70f)); offsetAnimator.addUpdateListener(animation -> { float val = (Float) animation.getAnimatedValue(); floatingAutoAnimator.setOffsetY(val); floatingButtonContainer.setAlpha(1f - (val / AndroidUtilities.dpf2(70f))); }); showDoneAnimation[currentDoneType].play(offsetAnimator); } } showDoneAnimation[currentDoneType].addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (showDoneAnimation[floating ? 0 : 1] != null && showDoneAnimation[floating ? 0 : 1].equals(animation)) { if (!show) { if (floating) { floatingButtonContainer.setVisibility(View.GONE); } if (floating && floatingButtonIcon.getAlpha() != 1f) { floatingButtonIcon.setAlpha(1f); floatingButtonIcon.setScaleX(1f); floatingButtonIcon.setScaleY(1f); floatingButtonIcon.setVisibility(View.VISIBLE); floatingButtonContainer.setEnabled(true); floatingProgressView.setAlpha(0f); floatingProgressView.setScaleX(0.1f); floatingProgressView.setScaleY(0.1f); floatingProgressView.setVisibility(View.INVISIBLE); } } } } @Override public void onAnimationCancel(Animator animation) { if (showDoneAnimation[floating ? 0 : 1] != null && showDoneAnimation[floating ? 0 : 1].equals(animation)) { showDoneAnimation[floating ? 0 : 1] = null; } } }); final int duration; final Interpolator interpolator; if (floating) { if (show) { duration = 200; interpolator = AndroidUtilities.decelerateInterpolator; } else { duration = 150; interpolator = AndroidUtilities.accelerateInterpolator; } } else { duration = 150; interpolator = null; } showDoneAnimation[currentDoneType].setDuration(duration); showDoneAnimation[currentDoneType].setInterpolator(interpolator); showDoneAnimation[currentDoneType].start(); } else { if (show) { if (floating) { floatingButtonContainer.setVisibility(View.VISIBLE); floatingAutoAnimator.setOffsetY(0f); } } else { if (floating) { floatingButtonContainer.setVisibility(View.GONE); floatingAutoAnimator.setOffsetY(AndroidUtilities.dpf2(70f)); } } } } private void onDoneButtonPressed() { if (!doneButtonVisible[currentDoneType]) { return; } if (radialProgressView.getTag() != null) { if (getParentActivity() == null) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString(R.string.NekoX)); builder.setMessage(LocaleController.getString("StopLoading", R.string.StopLoading)); builder.setPositiveButton(LocaleController.getString("WaitMore", R.string.WaitMore), null); builder.setNegativeButton(LocaleController.getString("Stop", R.string.Stop), (dialogInterface, i) -> { views[currentViewNum].onCancelPressed(); needHideProgress(true); }); showDialog(builder.create()); } else { views[currentViewNum].onNextPressed(null); } } private void showEditDoneProgress(boolean show, boolean animated) { showEditDoneProgress(show, animated, false); } private void showEditDoneProgress(boolean show, boolean animated, boolean fromCallback) { if (animated && doneProgressVisible[currentDoneType] == show && !fromCallback) { return; } boolean floating = currentDoneType == DONE_TYPE_FLOATING; if (!fromCallback && !floating) { doneProgressVisible[currentDoneType] = show; int doneType = currentDoneType; if (animated) { if (postedEditDoneCallback[currentDoneType]) { AndroidUtilities.cancelRunOnUIThread(editDoneCallback[currentDoneType]); postedEditDoneCallback[currentDoneType] = false; return; } else if (show) { AndroidUtilities.runOnUIThread(editDoneCallback[currentDoneType] = () -> { int type = currentDoneType; currentDoneType = doneType; showEditDoneProgress(show, animated, true); currentDoneType = type; }, 2000); postedEditDoneCallback[currentDoneType] = true; return; } } } else { postedEditDoneCallback[currentDoneType] = false; doneProgressVisible[currentDoneType] = show; } if (doneItemAnimation != null) { doneItemAnimation.cancel(); } if (animated) { doneItemAnimation = new AnimatorSet(); ValueAnimator animator = ValueAnimator.ofFloat(show ? 0 : 1, show ? 1 : 0); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { if (show) { if (floating) { floatingButtonIcon.setVisibility(View.VISIBLE); floatingProgressView.setVisibility(View.VISIBLE); floatingButtonContainer.setEnabled(false); } else { radialProgressView.setVisibility(View.VISIBLE); } } } @Override public void onAnimationEnd(Animator animation) { if (floating) { if (!show) { floatingProgressView.setVisibility(View.INVISIBLE); floatingButtonIcon.setVisibility(View.VISIBLE); floatingButtonContainer.setEnabled(true); } else { floatingButtonIcon.setVisibility(View.INVISIBLE); floatingProgressView.setVisibility(View.VISIBLE); } } else if (!show) { radialProgressView.setVisibility(View.INVISIBLE); } if (doneItemAnimation != null && doneItemAnimation.equals(animation)) { doneItemAnimation = null; } } }); animator.addUpdateListener(animation -> { float val = (float) animation.getAnimatedValue(); if (floating) { float scale = 0.1f + 0.9f * (1f - val); floatingButtonIcon.setScaleX(scale); floatingButtonIcon.setScaleY(scale); floatingButtonIcon.setAlpha(1f - val); scale = 0.1f + 0.9f * val; floatingProgressView.setScaleX(scale); floatingProgressView.setScaleY(scale); floatingProgressView.setAlpha(val); } else { float scale = 0.1f + 0.9f * val; radialProgressView.setScaleX(scale); radialProgressView.setScaleY(scale); radialProgressView.setAlpha(val); } }); doneItemAnimation.playTogether(animator); doneItemAnimation.setDuration(150); doneItemAnimation.start(); } else { if (show) { if (floating) { floatingProgressView.setVisibility(View.VISIBLE); floatingButtonIcon.setVisibility(View.INVISIBLE); floatingButtonContainer.setEnabled(false); floatingButtonIcon.setScaleX(0.1f); floatingButtonIcon.setScaleY(0.1f); floatingButtonIcon.setAlpha(0.0f); floatingProgressView.setScaleX(1.0f); floatingProgressView.setScaleY(1.0f); floatingProgressView.setAlpha(1.0f); } else { radialProgressView.setVisibility(View.VISIBLE); radialProgressView.setScaleX(1.0f); radialProgressView.setScaleY(1.0f); radialProgressView.setAlpha(1.0f); } } else { radialProgressView.setTag(null); if (floating) { floatingProgressView.setVisibility(View.INVISIBLE); floatingButtonIcon.setVisibility(View.VISIBLE); floatingButtonContainer.setEnabled(true); floatingProgressView.setScaleX(0.1f); floatingProgressView.setScaleY(0.1f); floatingProgressView.setAlpha(0.0f); floatingButtonIcon.setScaleX(1.0f); floatingButtonIcon.setScaleY(1.0f); floatingButtonIcon.setAlpha(1.0f); } else { radialProgressView.setVisibility(View.INVISIBLE); radialProgressView.setScaleX(0.1f); radialProgressView.setScaleY(0.1f); radialProgressView.setAlpha(0.0f); } } } } private void needShowProgress(int requestId) { needShowProgress(requestId, true); } private void needShowProgress(int requestId, boolean animated) { if (cancelAccountDeletionMode && requestId == 0) { if (cancelDeleteProgressDialog != null || getParentActivity() == null || getParentActivity().isFinishing()) { return; } cancelDeleteProgressDialog = new AlertDialog(getParentActivity(), 3); cancelDeleteProgressDialog.setCanCancel(false); cancelDeleteProgressDialog.show(); return; } progressRequestId = requestId; showEditDoneProgress(true, animated); } private void needHideProgress(boolean cancel) { needHideProgress(cancel, true); } private void needHideProgress(boolean cancel, boolean animated) { if (progressRequestId != 0) { if (cancel) { ConnectionsManager.getInstance(currentAccount).cancelRequest(progressRequestId, true); } progressRequestId = 0; } if (cancelAccountDeletionMode && cancelDeleteProgressDialog != null) { cancelDeleteProgressDialog.dismiss(); cancelDeleteProgressDialog = null; } showEditDoneProgress(false, animated); } public void setPage(@ViewNumber int page, boolean animated, Bundle params, boolean back) { boolean needFloatingButton = page == VIEW_PHONE_INPUT || page == VIEW_REGISTER || page == VIEW_PASSWORD || page == VIEW_NEW_PASSWORD_STAGE_1 || page == VIEW_NEW_PASSWORD_STAGE_2; if (needFloatingButton) { if (page == VIEW_PHONE_INPUT) { checkPermissions = true; checkShowPermissions = true; } currentDoneType = DONE_TYPE_ACTION; showDoneButton(false, animated); // Force reset radial progress showEditDoneProgress(false, animated); currentDoneType = DONE_TYPE_FLOATING; showEditDoneProgress(false, animated); if (!animated) { showDoneButton(true, false); } } else { currentDoneType = DONE_TYPE_FLOATING; showDoneButton(false, animated); showEditDoneProgress(false, animated); if (page != VIEW_RESET_WAIT) { currentDoneType = DONE_TYPE_ACTION; } } if (animated) { final SlideView outView = views[currentViewNum]; final SlideView newView = views[page]; currentViewNum = page; backButtonView.setVisibility(newView.needBackButton() || newAccount ? View.VISIBLE : View.GONE); newView.setParams(params, false); setParentActivityTitle(newView.getHeaderName()); newView.onShow(); newView.setX(back ? -AndroidUtilities.displaySize.x : AndroidUtilities.displaySize.x); newView.setVisibility(View.VISIBLE); AnimatorSet pagesAnimation = new AnimatorSet(); pagesAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (currentDoneType == DONE_TYPE_FLOATING && needFloatingButton) { showDoneButton(true, true); } outView.setVisibility(View.GONE); outView.setX(0); } }); pagesAnimation.playTogether( ObjectAnimator.ofFloat(outView, View.TRANSLATION_X, back ? AndroidUtilities.displaySize.x : -AndroidUtilities.displaySize.x), ObjectAnimator.ofFloat(newView, View.TRANSLATION_X, 0)); pagesAnimation.setDuration(300); pagesAnimation.setInterpolator(new AccelerateDecelerateInterpolator()); pagesAnimation.start(); setCustomKeyboardVisible(newView.hasCustomKeyboard(), true); } else { backButtonView.setVisibility(views[page].needBackButton() || newAccount ? View.VISIBLE : View.GONE); views[currentViewNum].setVisibility(View.GONE); currentViewNum = page; views[page].setParams(params, false); views[page].setVisibility(View.VISIBLE); setParentActivityTitle(views[page].getHeaderName()); views[page].onShow(); setCustomKeyboardVisible(views[page].hasCustomKeyboard(), false); } } @Override public void saveSelfArgs(Bundle outState) { try { Bundle bundle = new Bundle(); bundle.putInt("currentViewNum", currentViewNum); bundle.putInt("syncContacts", syncContacts ? 1 : 0); for (int a = 0; a <= currentViewNum; a++) { SlideView v = views[a]; if (v != null) { v.saveStateParams(bundle); } } SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo2", Context.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); editor.clear(); putBundleToEditor(bundle, editor, null); editor.commit(); } catch (Exception e) { FileLog.e(e); } } private void needFinishActivity(boolean afterSignup, boolean showSetPasswordConfirm, int otherwiseRelogin) { SharedConfig.activeAccounts.add(currentAccount); SharedConfig.saveAccounts(); if (getParentActivity() != null) { AndroidUtilities.setLightStatusBar(getParentActivity().getWindow(), false); } clearCurrentState(); if (getParentActivity() instanceof LaunchActivity) { if (newAccount) { newAccount = false; ((LaunchActivity) getParentActivity()).switchToAccount(currentAccount, false, obj -> { Bundle args = new Bundle(); args.putBoolean("afterSignup", afterSignup); return new DialogsActivity(args); }); finishFragment(); } else { if (afterSignup && showSetPasswordConfirm) { TwoStepVerificationSetupActivity twoStepVerification = new TwoStepVerificationSetupActivity(TwoStepVerificationSetupActivity.TYPE_INTRO, null); twoStepVerification.setBlockingAlert(otherwiseRelogin); twoStepVerification.setFromRegistration(true); presentFragment(twoStepVerification, true); } else { Bundle args = new Bundle(); args.putBoolean("afterSignup", afterSignup); DialogsActivity dialogsActivity = new DialogsActivity(args); presentFragment(dialogsActivity, true); } NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); LocaleController.getInstance().loadRemoteLanguages(currentAccount); } } else if (getParentActivity() instanceof ExternalActionActivity) { ((ExternalActionActivity) getParentActivity()).onFinishLogin(); } } private void onAuthSuccess(TLRPC.TL_auth_authorization res) { onAuthSuccess(res, false); } private void onAuthSuccess(TLRPC.TL_auth_authorization res, boolean afterSignup) { MessagesController.getInstance(currentAccount).cleanup(); ConnectionsManager.getInstance(currentAccount).setUserId(res.user.id); UserConfig.getInstance(currentAccount).clearConfig(); MessagesController.getInstance(currentAccount).cleanup(); UserConfig.getInstance(currentAccount).syncContacts = syncContacts; UserConfig.getInstance(currentAccount).setCurrentUser(res.user); UserConfig.getInstance(currentAccount).saveConfig(true); MessagesStorage.getInstance(currentAccount).cleanup(true); ArrayList users = new ArrayList<>(); users.add(res.user); MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, true, true); MessagesController.getInstance(currentAccount).putUser(res.user, false); ContactsController.getInstance(currentAccount).checkAppAccount(); MessagesController.getInstance(currentAccount).checkPromoInfo(true); ConnectionsManager.getInstance(currentAccount).updateDcSettings(); if (afterSignup) { MessagesController.getInstance(currentAccount).putDialogsEndReachedAfterRegistration(); } MediaDataController.getInstance(currentAccount).loadStickersByEmojiOrName(AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME, false, true); needFinishActivity(afterSignup, res.setup_password_required, res.otherwise_relogin_days); } private void fillNextCodeParams(Bundle params, TLRPC.TL_auth_sentCode res) { fillNextCodeParams(params, res, true); } private void fillNextCodeParams(Bundle params, TLRPC.TL_auth_sentCode res, boolean animate) { params.putString("phoneHash", res.phone_code_hash); if (res.next_type instanceof TLRPC.TL_auth_codeTypeCall) { params.putInt("nextType", AUTH_TYPE_CALL); } else if (res.next_type instanceof TLRPC.TL_auth_codeTypeFlashCall) { params.putInt("nextType", AUTH_TYPE_FLASH_CALL); } else if (res.next_type instanceof TLRPC.TL_auth_codeTypeSms) { params.putInt("nextType", AUTH_TYPE_SMS); } else if (res.next_type instanceof TLRPC.TL_auth_codeTypeMissedCall) { params.putInt("nextType", AUTH_TYPE_MISSED_CALL); } if (res.type instanceof TLRPC.TL_auth_sentCodeTypeApp) { params.putInt("type", 1); params.putInt("length", res.type.length); setPage(VIEW_CODE_MESSAGE, animate, params, false); } else { if (res.timeout == 0) { res.timeout = 60; } params.putInt("timeout", res.timeout * 1000); if (res.type instanceof TLRPC.TL_auth_sentCodeTypeCall) { params.putInt("type", 4); params.putInt("length", res.type.length); setPage(VIEW_CODE_CALL, animate, params, false); } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeFlashCall) { params.putInt("type", 3); params.putString("pattern", res.type.pattern); setPage(VIEW_CODE_FLASH_CALL, animate, params, false); } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeSms) { params.putInt("type", 2); params.putInt("length", res.type.length); setPage(VIEW_CODE_SMS, animate, params, false); } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeMissedCall) { params.putInt("type", AUTH_TYPE_MISSED_CALL); params.putInt("length", res.type.length); params.putString("prefix", res.type.prefix); setPage(VIEW_CODE_MISSED_CALL, animate, params, false); } } } private TLRPC.TL_help_termsOfService currentTermsOfService; public class PhoneView extends SlideView implements AdapterView.OnItemSelectedListener, NotificationCenter.NotificationCenterDelegate { private AnimatedPhoneNumberEditText codeField; private AnimatedPhoneNumberEditText phoneField; private TextView titleView; private TextViewSwitcher countryButton; private OutlineTextContainerView countryOutlineView; private OutlineTextContainerView phoneOutlineView; private TextView plusTextView; private TextView subtitleView; private View codeDividerView; private ImageView chevronRight; private CheckBoxCell syncContactsBox; private CheckBoxCell testBackendCheckBox; @CountryState private int countryState = COUNTRY_STATE_NOT_SET_OR_VALID; private CountrySelectActivity.Country currentCountry; private ArrayList countriesArray = new ArrayList<>(); private HashMap codesMap = new HashMap<>(); private HashMap phoneFormatMap = new HashMap<>(); private boolean ignoreSelection = false; private boolean ignoreOnTextChange = false; private boolean ignoreOnPhoneChange = false; private boolean nextPressed = false; private boolean confirmedNumber = false; public PhoneView(Context context) { super(context); setOrientation(VERTICAL); setGravity(Gravity.CENTER); titleView = new TextView(context); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleView.setText(LocaleController.getString(R.string.YourNumber)); titleView.setGravity(Gravity.CENTER); titleView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 32, 0, 32, 0)); subtitleView = new TextView(context); subtitleView.setText(LocaleController.getString("StartText", R.string.StartText)); subtitleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); subtitleView.setGravity(Gravity.CENTER); subtitleView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); addView(subtitleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 32, 8, 32, 0)); countryButton = new TextViewSwitcher(context); countryButton.setFactory(() -> { TextView tv = new TextView(context); tv.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(12), AndroidUtilities.dp(16), AndroidUtilities.dp(12)); tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); tv.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); tv.setHintTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText)); tv.setMaxLines(1); tv.setSingleLine(true); tv.setEllipsize(TextUtils.TruncateAt.END); tv.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_HORIZONTAL); return tv; }); Animation anim = AnimationUtils.loadAnimation(context, R.anim.text_in); anim.setInterpolator(Easings.easeInOutQuad); countryButton.setInAnimation(anim); chevronRight = new ImageView(context); chevronRight.setImageResource(R.drawable.msg_inputarrow); LinearLayout countryButtonLinearLayout = new LinearLayout(context); countryButtonLinearLayout.setOrientation(HORIZONTAL); countryButtonLinearLayout.setGravity(Gravity.CENTER_VERTICAL); countryButtonLinearLayout.addView(countryButton, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 0, 0)); countryButtonLinearLayout.addView(chevronRight, LayoutHelper.createLinearRelatively(24, 24, 0, 0, 0, 14, 0)); countryOutlineView = new OutlineTextContainerView(context); countryOutlineView.setText(LocaleController.getString(R.string.Country)); countryOutlineView.addView(countryButtonLinearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 0, 0, 0, 0)); countryOutlineView.setForceUseCenter(true); countryOutlineView.setFocusable(true); countryOutlineView.setContentDescription(LocaleController.getString(R.string.Country)); countryOutlineView.setOnFocusChangeListener((v, hasFocus) -> countryOutlineView.animateSelection(hasFocus ? 1 : 0)); addView(countryOutlineView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 58, 16, 24, 16, 14)); countryOutlineView.setOnClickListener(view -> { CountrySelectActivity fragment = new CountrySelectActivity(true, countriesArray); fragment.setCountrySelectActivityDelegate((country) -> { selectCountry(country); AndroidUtilities.runOnUIThread(() -> showKeyboard(phoneField), 300); phoneField.requestFocus(); phoneField.setSelection(phoneField.length()); }); presentFragment(fragment); }); LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(HORIZONTAL); phoneOutlineView = new OutlineTextContainerView(context); phoneOutlineView.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 16, 8, 16, 8)); phoneOutlineView.setText(LocaleController.getString(R.string.PhoneNumber)); addView(phoneOutlineView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 58, 16, 8, 16, 8)); plusTextView = new TextView(context); plusTextView.setText("+"); plusTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); plusTextView.setFocusable(false); linearLayout.addView(plusTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); codeField = new AnimatedPhoneNumberEditText(context) { @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { super.onFocusChanged(focused, direction, previouslyFocusedRect); phoneOutlineView.animateSelection(focused || phoneField.isFocused() ? 1f : 0f); if (focused) { keyboardView.setEditText(this); } } }; codeField.setInputType(InputType.TYPE_CLASS_PHONE); codeField.setCursorSize(AndroidUtilities.dp(20)); codeField.setCursorWidth(1.5f); codeField.setPadding(AndroidUtilities.dp(10), 0, 0, 0); codeField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); codeField.setMaxLines(1); codeField.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); codeField.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI); codeField.setBackground(null); // codeField.setLineColors(getThemedColor(Theme.key_windowBackgroundWhiteInputField), getThemedColor(Theme.key_windowBackgroundWhiteInputFieldActivated), getThemedColor(Theme.key_windowBackgroundWhiteRedText3)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { codeField.setShowSoftInputOnFocus(!(hasCustomKeyboard() && !isCustomKeyboardForceDisabled())); } codeField.setContentDescription(LocaleController.getString(R.string.LoginAccessibilityCountryCode)); linearLayout.addView(codeField, LayoutHelper.createLinear(55, 36, -9, 0, 0, 0)); codeField.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { } @Override public void afterTextChanged(Editable editable) { if (ignoreOnTextChange) { return; } ignoreOnTextChange = true; String text = PhoneFormat.stripExceptNumbers(codeField.getText().toString()); codeField.setText(text); if (text.length() == 0) { setCountryButtonText(null); phoneField.setHintText(null); countryState = COUNTRY_STATE_EMPTY; } else { CountrySelectActivity.Country country; boolean ok = false; String textToSet = null; if (text.length() > 4) { for (int a = 4; a >= 1; a--) { String sub = text.substring(0, a); country = codesMap.get(sub); if (country != null) { ok = true; textToSet = text.substring(a) + phoneField.getText().toString(); codeField.setText(text = sub); break; } } if (!ok) { textToSet = text.substring(1) + phoneField.getText().toString(); codeField.setText(text = text.substring(0, 1)); } } CountrySelectActivity.Country lastMatchedCountry = null; int matchedCountries = 0; for (CountrySelectActivity.Country c : codesMap.values()) { if (c.code.startsWith(text)) { matchedCountries++; if (c.code.equals(text)) { lastMatchedCountry = c; } } } if (matchedCountries == 1 && lastMatchedCountry != null && textToSet == null) { textToSet = text.substring(lastMatchedCountry.code.length()) + phoneField.getText().toString(); codeField.setText(text = lastMatchedCountry.code); } country = codesMap.get(text); if (country != null) { ignoreSelection = true; currentCountry = country; setCountryHint(text, country); countryState = COUNTRY_STATE_NOT_SET_OR_VALID; } else { setCountryButtonText(null); phoneField.setHintText(null); countryState = COUNTRY_STATE_INVALID; } if (!ok) { codeField.setSelection(codeField.getText().length()); } if (textToSet != null) { phoneField.requestFocus(); phoneField.setText(textToSet); phoneField.setSelection(phoneField.length()); } } ignoreOnTextChange = false; } }); codeField.setOnEditorActionListener((textView, i, keyEvent) -> { if (i == EditorInfo.IME_ACTION_NEXT) { phoneField.requestFocus(); phoneField.setSelection(phoneField.length()); return true; } return false; }); codeDividerView = new View(context); LayoutParams params = LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 4, 8, 12, 8); params.width = Math.max(2, AndroidUtilities.dp(0.5f)); linearLayout.addView(codeDividerView, params); phoneField = new AnimatedPhoneNumberEditText(context) { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DEL && phoneField.length() == 0) { codeField.requestFocus(); codeField.setSelection(codeField.length()); codeField.dispatchKeyEvent(event); } return super.onKeyDown(keyCode, event); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (!showKeyboard(this)) { clearFocus(); requestFocus(); } } return super.onTouchEvent(event); } @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { super.onFocusChanged(focused, direction, previouslyFocusedRect); phoneOutlineView.animateSelection(focused || codeField.isFocused() ? 1f : 0f); if (focused) { keyboardView.setEditText(this); keyboardView.setDispatchBackWhenEmpty(true); if (countryState == COUNTRY_STATE_INVALID) { setCountryButtonText(LocaleController.getString(R.string.WrongCountry)); } } else { if (countryState == COUNTRY_STATE_INVALID) { setCountryButtonText(null); } } } }; phoneField.setInputType(InputType.TYPE_CLASS_PHONE); phoneField.setPadding(0, 0, 0, 0); phoneField.setCursorSize(AndroidUtilities.dp(20)); phoneField.setCursorWidth(1.5f); phoneField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); phoneField.setMaxLines(1); phoneField.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); phoneField.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI); phoneField.setBackground(null); // phoneField.setLineColors(getThemedColor(Theme.key_windowBackgroundWhiteInputField), getThemedColor(Theme.key_windowBackgroundWhiteInputFieldActivated), getThemedColor(Theme.key_windowBackgroundWhiteRedText3)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { phoneField.setShowSoftInputOnFocus(!(hasCustomKeyboard() && !isCustomKeyboardForceDisabled())); } phoneField.setContentDescription(LocaleController.getString(R.string.PhoneNumber)); linearLayout.addView(phoneField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36)); phoneField.addTextChangedListener(new TextWatcher() { private int characterAction = -1; private int actionPosition; @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { if (count == 0 && after == 1) { characterAction = 1; } else if (count == 1 && after == 0) { if (s.charAt(start) == ' ' && start > 0) { characterAction = 3; actionPosition = start - 1; } else { characterAction = 2; } } else { characterAction = -1; } } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { if (ignoreOnPhoneChange) { return; } int start = phoneField.getSelectionStart(); String phoneChars = "0123456789"; String str = phoneField.getText().toString(); if (characterAction == 3) { str = str.substring(0, actionPosition) + str.substring(actionPosition + 1); start--; } StringBuilder builder = new StringBuilder(str.length()); for (int a = 0; a < str.length(); a++) { String ch = str.substring(a, a + 1); if (phoneChars.contains(ch)) { builder.append(ch); } } ignoreOnPhoneChange = true; String hint = phoneField.getHintText(); if (hint != null) { for (int a = 0; a < builder.length(); a++) { if (a < hint.length()) { if (hint.charAt(a) == ' ') { builder.insert(a, ' '); a++; if (start == a && characterAction != 2 && characterAction != 3) { start++; } } } else { builder.insert(a, ' '); if (start == a + 1 && characterAction != 2 && characterAction != 3) { start++; } break; } } } s.replace(0, s.length(), builder); if (start >= 0) { phoneField.setSelection(Math.min(start, phoneField.length())); } phoneField.onTextChange(); ignoreOnPhoneChange = false; } }); phoneField.setOnEditorActionListener((textView, i, keyEvent) -> { if (i == EditorInfo.IME_ACTION_NEXT) { if (phoneNumberConfirmView != null) { phoneNumberConfirmView.popupFabContainer.callOnClick(); return true; } onNextPressed(null); return true; } return false; }); int bottomMargin = 72; syncContactsBox = new CheckBoxCell(context, 2); syncContactsBox.setText(LocaleController.getString("SyncContacts", R.string.SyncContacts), "", syncContacts, false); addView(syncContactsBox, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 16, 0, 16 + (LocaleController.isRTL && AndroidUtilities.isSmallScreen() ? Build.VERSION.SDK_INT >= 21 ? 56 : 60 : 0), 0)); bottomMargin -= 24; syncContactsBox.setOnClickListener(v -> { if (getParentActivity() == null) { return; } CheckBoxCell cell = (CheckBoxCell) v; syncContacts = !syncContacts; cell.setChecked(syncContacts, true); if (syncContacts) { BulletinFactory.of(slideViewsContainer, null).createSimpleBulletin(R.raw.contacts_sync_on, LocaleController.getString("SyncContactsOn", R.string.SyncContactsOn)).show(); } else { BulletinFactory.of(slideViewsContainer, null).createSimpleBulletin(R.raw.contacts_sync_off, LocaleController.getString("SyncContactsOff", R.string.SyncContactsOff)).show(); } }); if (BuildVars.DEBUG_PRIVATE_VERSION) { testBackendCheckBox = new CheckBoxCell(context, 2); testBackendCheckBox.setText("Test Backend", "", testBackend, false); addView(testBackendCheckBox, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 16, 0, 16 + (LocaleController.isRTL && AndroidUtilities.isSmallScreen() ? Build.VERSION.SDK_INT >= 21 ? 56 : 60 : 0), 0)); bottomMargin -= 24; testBackendCheckBox.setOnClickListener(v -> { if (getParentActivity() == null) { return; } CheckBoxCell cell = (CheckBoxCell) v; testBackend = !testBackend; cell.setChecked(testBackend, true); }); } if (bottomMargin > 0 && !AndroidUtilities.isSmallScreen()) { Space bottomSpacer = new Space(context); bottomSpacer.setMinimumHeight(AndroidUtilities.dp(bottomMargin)); addView(bottomSpacer, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); } HashMap languageMap = new HashMap<>(); try { BufferedReader reader = new BufferedReader(new InputStreamReader(getResources().getAssets().open("countries.txt"))); String line; while ((line = reader.readLine()) != null) { String[] args = line.split(";"); CountrySelectActivity.Country countryWithCode = new CountrySelectActivity.Country(); countryWithCode.name = args[2]; countryWithCode.code = args[0]; countryWithCode.shortname = args[1]; countriesArray.add(0, countryWithCode); codesMap.put(args[0], countryWithCode); if (args.length > 3) { phoneFormatMap.put(args[0], args[3]); } languageMap.put(args[1], args[2]); } reader.close(); } catch (Exception e) { FileLog.e(e); } Collections.sort(countriesArray, Comparator.comparing(o -> o.name)); String country = null; // NekoX: Remove TelephonyManager // try { // TelephonyManager telephonyManager = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); // if (telephonyManager != null) { // country = null;//telephonyManager.getSimCountryIso().toUpperCase(); // } // } catch (Exception e) { // FileLog.e(e); // } if (country != null) { setCountry(languageMap, country.toUpperCase()); } else { TLRPC.TL_help_getNearestDc req = new TLRPC.TL_help_getNearestDc(); getAccountInstance().getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (response == null) { return; } TLRPC.TL_nearestDc res = (TLRPC.TL_nearestDc) response; if (codeField.length() == 0) { setCountry(languageMap, res.country.toUpperCase()); } }), ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); } if (codeField.length() == 0) { setCountryButtonText(null); phoneField.setHintText(null); countryState = COUNTRY_STATE_EMPTY; } if (codeField.length() != 0) { phoneField.requestFocus(); phoneField.setSelection(phoneField.length()); } else { codeField.requestFocus(); } TLRPC.TL_help_getCountriesList req = new TLRPC.TL_help_getCountriesList(); req.lang_code = ""; getConnectionsManager().sendRequest(req, (response, error) -> { AndroidUtilities.runOnUIThread(() -> { if (error == null) { countriesArray.clear(); codesMap.clear(); phoneFormatMap.clear(); TLRPC.TL_help_countriesList help_countriesList = (TLRPC.TL_help_countriesList) response; for (int i = 0; i < help_countriesList.countries.size(); i++) { TLRPC.TL_help_country c = help_countriesList.countries.get(i); for (int k = 0; k < c.country_codes.size(); k++) { CountrySelectActivity.Country countryWithCode = new CountrySelectActivity.Country(); countryWithCode.name = c.default_name; countryWithCode.code = c.country_codes.get(k).country_code; countryWithCode.shortname = c.iso2; countriesArray.add(countryWithCode); codesMap.put(c.country_codes.get(k).country_code, countryWithCode); if (c.country_codes.get(k).patterns.size() > 0) { phoneFormatMap.put(c.country_codes.get(k).country_code, c.country_codes.get(k).patterns.get(0)); } } } CountrySelectActivity.Country countryWithCode = new CountrySelectActivity.Country(); String test_code = "999"; countryWithCode.name = "Test Number"; countryWithCode.code = test_code; countryWithCode.shortname = "YL"; countriesArray.add(countryWithCode); codesMap.put(test_code, countryWithCode); phoneFormatMap.put(test_code, "XX X XXXX"); } }); }, ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); } @Override public void updateColors() { titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); subtitleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); for (int i = 0; i < countryButton.getChildCount(); i++) { TextView textView = (TextView) countryButton.getChildAt(i); textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); textView.setHintTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText)); } chevronRight.setColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteHintText)); chevronRight.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), 1)); plusTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); codeField.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); codeField.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated)); codeDividerView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputField)); phoneField.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); phoneField.setHintTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText)); phoneField.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated)); if (syncContactsBox != null) { syncContactsBox.setSquareCheckBoxColor(Theme.key_checkboxSquareUnchecked, Theme.key_checkboxSquareBackground, Theme.key_checkboxSquareCheck); syncContactsBox.updateTextColor(); } if (testBackendCheckBox != null) { testBackendCheckBox.setSquareCheckBoxColor(Theme.key_checkboxSquareUnchecked, Theme.key_checkboxSquareBackground, Theme.key_checkboxSquareCheck); testBackendCheckBox.updateTextColor(); } phoneOutlineView.updateColor(); countryOutlineView.updateColor(); } @Override public boolean hasCustomKeyboard() { return true; } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); } public void selectCountry(CountrySelectActivity.Country country) { ignoreOnTextChange = true; String code = country.code; codeField.setText(code); setCountryHint(code, country); currentCountry = country; countryState = COUNTRY_STATE_NOT_SET_OR_VALID; ignoreOnTextChange = false; } private void setCountryHint(String code, CountrySelectActivity.Country country) { SpannableStringBuilder sb = new SpannableStringBuilder(); String flag = LocaleController.getLanguageFlag(country.shortname); if (flag != null) { sb.append(flag).append(" "); sb.setSpan(new ReplacementSpan() { @Override public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { return AndroidUtilities.dp(16); } @Override public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {} }, flag.length(), flag.length() + 1, 0); } sb.append(country.name); setCountryButtonText(Emoji.replaceEmoji(sb, countryButton.getCurrentView().getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false)); String hint = phoneFormatMap.get(code); phoneField.setHintText(hint != null ? hint.replace('X', '0') : null); } private void setCountryButtonText(CharSequence cs) { Animation anim = AnimationUtils.loadAnimation(ApplicationLoader.applicationContext, countryButton.getCurrentView().getText() != null && cs == null ? R.anim.text_out_down : R.anim.text_out); anim.setInterpolator(Easings.easeInOutQuad); countryButton.setOutAnimation(anim); CharSequence prevText = countryButton.getCurrentView().getText(); countryButton.setText(cs, !(TextUtils.isEmpty(cs) && TextUtils.isEmpty(prevText)) && !Objects.equals(prevText, cs)); countryOutlineView.animateSelection(cs != null ? 1f : 0f); } private void setCountry(HashMap languageMap, String country) { String name = languageMap.get(country); if (name != null && countriesArray != null) { CountrySelectActivity.Country countryWithCode = null; for (int i = 0; i < countriesArray.size(); i++) { if (countriesArray.get(i) != null && countriesArray.get(i).name.equals(country)) { countryWithCode = countriesArray.get(i); break; } } if (countryWithCode != null) { codeField.setText(countryWithCode.code); countryState = COUNTRY_STATE_NOT_SET_OR_VALID; } } } @Override public void onCancelPressed() { nextPressed = false; } @Override public void onItemSelected(AdapterView adapterView, View view, int i, long l) { if (ignoreSelection) { ignoreSelection = false; return; } ignoreOnTextChange = true; CountrySelectActivity.Country countryWithCode = countriesArray.get(i); codeField.setText(countryWithCode.code); ignoreOnTextChange = false; } @Override public void onNothingSelected(AdapterView adapterView) { } @Override public void onNextPressed(String code) { if (getParentActivity() == null || nextPressed) { return; } // TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); // if (BuildVars.DEBUG_VERSION) { // FileLog.d("sim status = " + tm.getSimState()); // } if (codeField.length() == 0 || phoneField.length() == 0) { onFieldError(phoneOutlineView, false); return; } String phoneNumber = "+" + codeField.getText() + " " + phoneField.getText(); String hintText = phoneField.getHintText(); int hintLength = hintText != null ? hintText.length() : 0; PhoneNumberExclusionRule exclusionRule = phoneNumberExclusionRules.get(codeField.getText().toString()); if (exclusionRule != null) { hintLength = exclusionRule.modifyHintLengthRequirement(hintLength); } if (hintText != null && phoneField.length() < hintLength) { new AlertDialog.Builder(getParentActivity()) .setTitle(LocaleController.getString(R.string.WrongNumberFormat)) .setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("ShortNumberInfo", R.string.ShortNumberInfo, currentCountry.name, phoneNumber))) .setPositiveButton(LocaleController.getString(R.string.OK), null) .setNegativeButton(LocaleController.getString(R.string.SettingsHelp), (dialog, which) -> { try { getParentActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://telegram.org/faq"))); } catch (ActivityNotFoundException ignored) {} }).show(); return; } if (!confirmedNumber) { if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y && !isCustomKeyboardVisible() && sizeNotifierFrameLayout.measureKeyboardHeight() > AndroidUtilities.dp(20)) { keyboardHideCallback = () -> postDelayed(()-> onNextPressed(code), 200); AndroidUtilities.hideKeyboard(fragmentView); return; } phoneNumberConfirmView = new PhoneNumberConfirmView(fragmentView.getContext(), (ViewGroup) fragmentView, floatingButtonContainer, phoneNumber, new PhoneNumberConfirmView.IConfirmDialogCallback() { @Override public void onFabPressed(PhoneNumberConfirmView confirmView, TransformableLoginButtonView fab) { onConfirm(confirmView); } @Override public void onEditPressed(PhoneNumberConfirmView confirmView, TextView editTextView) { confirmView.dismiss(); } @Override public void onConfirmPressed(PhoneNumberConfirmView confirmView, TextView confirmTextView) { onConfirm(confirmView); } @Override public void onDismiss(PhoneNumberConfirmView confirmView) { phoneNumberConfirmView = null; } private void onConfirm(PhoneNumberConfirmView confirmView) { confirmedNumber = true; currentDoneType = DONE_TYPE_FLOATING; needShowProgress(0, false); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && AndroidUtilities.isSimAvailable()) { boolean allowCall = getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; boolean allowCancelCall = getParentActivity().checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED; boolean allowReadCallLog = Build.VERSION.SDK_INT < Build.VERSION_CODES.P || getParentActivity().checkSelfPermission(Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED; boolean allowReadPhoneNumbers = Build.VERSION.SDK_INT < Build.VERSION_CODES.O || getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_GRANTED;; if (checkPermissions) { permissionsItems.clear(); if (!allowCall) { permissionsItems.add(Manifest.permission.READ_PHONE_STATE); } if (!allowCancelCall) { permissionsItems.add(Manifest.permission.CALL_PHONE); } if (!allowReadCallLog) { permissionsItems.add(Manifest.permission.READ_CALL_LOG); } if (!allowReadPhoneNumbers && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { permissionsItems.add(Manifest.permission.READ_PHONE_NUMBERS); } if (!permissionsItems.isEmpty()) { SharedPreferences preferences = MessagesController.getGlobalMainSettings(); if (preferences.getBoolean("firstlogin", true) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.READ_CALL_LOG)) { preferences.edit().putBoolean("firstlogin", false).commit(); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setPositiveButton(LocaleController.getString("Continue", R.string.Continue), null); int resId; if (!allowCall && (!allowCancelCall || !allowReadCallLog)) { builder.setMessage(LocaleController.getString("AllowReadCallAndLog", R.string.AllowReadCallAndLog)); resId = R.raw.calls_log; } else if (!allowCancelCall || !allowReadCallLog) { builder.setMessage(LocaleController.getString("AllowReadCallLog", R.string.AllowReadCallLog)); resId = R.raw.calls_log; } else { builder.setMessage(LocaleController.getString("AllowReadCall", R.string.AllowReadCall)); resId = R.raw.incoming_calls; } builder.setTopAnimation(resId, 46, false, Theme.getColor(Theme.key_dialogTopBackground)); permissionsDialog = showDialog(builder.create()); confirmedNumber = true; } else { try { getParentActivity().requestPermissions(permissionsItems.toArray(new String[0]), 6); } catch (Exception e) { FileLog.e(e); } } return; } } } confirmView.animateProgress(()->{ confirmView.dismiss(); AndroidUtilities.runOnUIThread(()-> { onNextPressed(code); floatingProgressView.sync(confirmView.floatingProgressView); }, 150); }); } }); phoneNumberConfirmView.show(); return; } else confirmedNumber = false; if (phoneNumberConfirmView != null) { phoneNumberConfirmView.dismiss(); } boolean simcardAvailable = AndroidUtilities.isSimAvailable(); boolean allowCall = true; boolean allowCancelCall = true; boolean allowReadCallLog = true; boolean allowReadPhoneNumbers = true; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && simcardAvailable) { allowCall = getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; allowCancelCall = getParentActivity().checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED; allowReadCallLog = Build.VERSION.SDK_INT < Build.VERSION_CODES.P || getParentActivity().checkSelfPermission(Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { allowReadPhoneNumbers = getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_GRANTED; } if (checkPermissions) { permissionsItems.clear(); if (!allowCall) { permissionsItems.add(Manifest.permission.READ_PHONE_STATE); } if (!allowCancelCall) { permissionsItems.add(Manifest.permission.CALL_PHONE); } if (!allowReadCallLog) { permissionsItems.add(Manifest.permission.READ_CALL_LOG); } if (!allowReadPhoneNumbers && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { permissionsItems.add(Manifest.permission.READ_PHONE_NUMBERS); } if (!permissionsItems.isEmpty()) { SharedPreferences preferences = MessagesController.getGlobalMainSettings(); if (preferences.getBoolean("firstlogin", true) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.READ_CALL_LOG)) { preferences.edit().putBoolean("firstlogin", false).commit(); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setPositiveButton(LocaleController.getString("Continue", R.string.Continue), null); int resId; if (!allowCall && (!allowCancelCall || !allowReadCallLog)) { builder.setMessage(LocaleController.getString("AllowReadCallAndLog", R.string.AllowReadCallAndLog)); resId = R.raw.calls_log; } else if (!allowCancelCall || !allowReadCallLog) { builder.setMessage(LocaleController.getString("AllowReadCallLog", R.string.AllowReadCallLog)); resId = R.raw.calls_log; } else { builder.setMessage(LocaleController.getString("AllowReadCall", R.string.AllowReadCall)); resId = R.raw.incoming_calls; } builder.setTopAnimation(resId, 46, false, Theme.getColor(Theme.key_dialogTopBackground)); permissionsDialog = showDialog(builder.create()); confirmedNumber = true; } else { try { getParentActivity().requestPermissions(permissionsItems.toArray(new String[0]), 6); } catch (Exception e) { FileLog.e(e); } } return; } } } if (countryState == COUNTRY_STATE_EMPTY) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("ChooseCountry", R.string.ChooseCountry)); needHideProgress(false); return; } else if (countryState == COUNTRY_STATE_INVALID && !BuildVars.DEBUG_VERSION) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("WrongCountry", R.string.WrongCountry)); needHideProgress(false); return; } String phone = PhoneFormat.stripExceptNumbers("" + codeField.getText() + phoneField.getText()); if (!testBackend && "999".equals(codeField.getText().toString())) { testBackend = true; if (testBackendCheckBox != null) { testBackendCheckBox.setChecked(true, true); } } boolean testBackend = /*BuildVars.DEBUG_PRIVATE_VERSION && */getConnectionsManager().isTestBackend(); if (testBackend != LoginActivity.this.testBackend) { getConnectionsManager().switchBackend(false); testBackend = LoginActivity.this.testBackend; } if (getParentActivity() instanceof LaunchActivity) { for (int a : SharedConfig.activeAccounts) { UserConfig userConfig = UserConfig.getInstance(a); if (!userConfig.isClientActivated()) { continue; } String userPhone = userConfig.getCurrentUser().phone; if (PhoneNumberUtils.compare(phone, userPhone) && ConnectionsManager.getInstance(a).isTestBackend() == testBackend) { final int num = a; AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString(R.string.NekoX)); builder.setMessage(LocaleController.getString("AccountAlreadyLoggedIn", R.string.AccountAlreadyLoggedIn)); builder.setPositiveButton(LocaleController.getString("AccountSwitch", R.string.AccountSwitch), (dialog, which) -> { if (UserConfig.selectedAccount != num) { ((LaunchActivity) getParentActivity()).switchToAccount(num, false); } finishFragment(); }); builder.setNegativeButton(LocaleController.getString("OK", R.string.OK), null); showDialog(builder.create()); needHideProgress(false); return; } } } ConnectionsManager.getInstance(currentAccount).cleanup(false); final TLRPC.TL_auth_sendCode req = new TLRPC.TL_auth_sendCode(); req.api_hash = NekoXConfig.currentAppHash(); req.api_id = NekoXConfig.currentAppId(); req.phone_number = phone; req.settings = new TLRPC.TL_codeSettings(); req.settings.allow_flashcall = simcardAvailable && allowCall && allowCancelCall && allowReadCallLog; req.settings.allow_missed_call = simcardAvailable && allowCall; req.settings.allow_app_hash = ApplicationLoader.hasPlayServices; ArrayList tokens = MessagesController.getSavedLogOutTokens(); if (tokens != null) { for (int i = 0; i < tokens.size(); i++) { if (req.settings.logout_tokens == null) { req.settings.logout_tokens = new ArrayList<>(); } req.settings.logout_tokens.add(tokens.get(i).future_auth_token); } MessagesController.saveLogOutTokens(tokens); } if (req.settings.logout_tokens != null) { req.settings.flags |= 64; } SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); if (req.settings.allow_flashcall) { try { String number = ""; if (!TextUtils.isEmpty(number)) { req.settings.current_number = PhoneNumberUtils.compare(phone, number); if (!req.settings.current_number) { req.settings.allow_flashcall = false; } } else { if (UserConfig.getActivatedAccountsCount() > 0) { req.settings.allow_flashcall = false; } else { req.settings.current_number = false; } } } catch (Exception e) { req.settings.allow_flashcall = false; FileLog.e(e); } } final Bundle params = new Bundle(); params.putString("phone", "+" + codeField.getText() + " " + phoneField.getText()); try { params.putString("ephone", "+" + PhoneFormat.stripExceptNumbers(codeField.getText().toString()) + " " + PhoneFormat.stripExceptNumbers(phoneField.getText().toString())); } catch (Exception e) { FileLog.e(e); params.putString("ephone", "+" + phone); } params.putString("phoneFormated", phone); nextPressed = true; int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { nextPressed = false; if (error == null) { fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); if (phone.startsWith("99966")) { fillNextCodeParamsSilent(params, (TLRPC.TL_auth_sentCode) response); String phoneHash = ((TLRPC.TL_auth_sentCode) response).phone_code_hash; String dcId = phone.substring(5, 6); final TLRPC.TL_auth_signIn reqI = new TLRPC.TL_auth_signIn(); reqI.phone_number = phone; reqI.phone_code = dcId + dcId + dcId + dcId + dcId; reqI.phone_code_hash = phoneHash; int reqIdI = ConnectionsManager.getInstance(currentAccount).sendRequest(reqI, (responseI, errorI) -> AndroidUtilities.runOnUIThread(() -> { boolean ok = false; if (errorI == null) { nextPressed = false; ok = true; showDoneButton(false, true); if (responseI instanceof TLRPC.TL_auth_authorizationSignUpRequired) { TLRPC.TL_auth_authorizationSignUpRequired authorization = (TLRPC.TL_auth_authorizationSignUpRequired) responseI; if (authorization.terms_of_service != null) { currentTermsOfService = authorization.terms_of_service; } Bundle paramsI = new Bundle(); paramsI.putString("phoneFormated", phone); paramsI.putString("phoneHash", phoneHash); paramsI.putString("code", reqI.phone_code); setPage(VIEW_REGISTER, true, params, false); } else { onAuthSuccess((TLRPC.TL_auth_authorization) responseI); } } else { if (errorI.text.contains("SESSION_PASSWORD_NEEDED")) { ok = true; TLRPC.TL_account_getPassword req2 = new TLRPC.TL_account_getPassword(); ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { nextPressed = false; showDoneButton(false, true); if (error1 == null) { TLRPC.TL_account_password password = (TLRPC.TL_account_password) response1; if (!TwoStepVerificationActivity.canHandleCurrentPassword(password, true)) { AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); return; } Bundle bundle = new Bundle(); SerializedData data = new SerializedData(password.getObjectSize()); password.serializeToStream(data); bundle.putString("password", Utilities.bytesToHex(data.toByteArray())); bundle.putString("phoneFormated", phone); bundle.putString("phoneHash", phoneHash); bundle.putString("code", reqI.phone_code); setPage(6, true, bundle, false); } else { needShowAlert(LocaleController.getString("NekoX", R.string.NekoX), error1.text); } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } else { nextPressed = false; showDoneButton(false, true); if (errorI.text.contains("PHONE_NUMBER_INVALID")) { needShowAlert(LocaleController.getString("NekoX", R.string.NekoX), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); } else if (errorI.text.contains("PHONE_CODE_EMPTY") || errorI.text.contains("PHONE_CODE_INVALID")) { needShowAlert(LocaleController.getString("NekoX", R.string.NekoX), LocaleController.getString("InvalidCode", R.string.InvalidCode)); } else if (errorI.text.contains("PHONE_CODE_EXPIRED")) { onBackPressed(true); setPage(VIEW_PHONE_INPUT, true, null, true); needShowAlert(LocaleController.getString("NekoX", R.string.NekoX), LocaleController.getString("CodeExpired", R.string.CodeExpired)); } else if (errorI.text.startsWith("FLOOD_WAIT")) { needShowAlert(LocaleController.getString("NekoX", R.string.NekoX), LocaleController.getString("FloodWait", R.string.FloodWait)); } else { needShowAlert(LocaleController.getString("NekoX", R.string.NekoX), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + errorI.text); } } } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); needShowProgress(reqIdI, false); showDoneButton(true, true); return; } } else { if (error.text != null) { if (error.text.contains("SESSION_PASSWORD_NEEDED")) { TLRPC.TL_account_getPassword req2 = new TLRPC.TL_account_getPassword(); ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { nextPressed = false; showDoneButton(false, true); if (error1 == null) { TLRPC.TL_account_password password = (TLRPC.TL_account_password) response1; if (!TwoStepVerificationActivity.canHandleCurrentPassword(password, true)) { AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); return; } Bundle bundle = new Bundle(); SerializedData data = new SerializedData(password.getObjectSize()); password.serializeToStream(data); bundle.putString("password", Utilities.bytesToHex(data.toByteArray())); bundle.putString("phoneFormated", phone); setPage(VIEW_PASSWORD, true, bundle, false); } else { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), error1.text); } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } else if (error.text.contains("PHONE_NUMBER_INVALID")) { needShowInvalidAlert(LoginActivity.this, req.phone_number, false); } else if (error.text.contains("PHONE_PASSWORD_FLOOD")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("FloodWait", R.string.FloodWait)); } else if (error.text.contains("PHONE_NUMBER_FLOOD")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("PhoneNumberFlood", R.string.PhoneNumberFlood)); } else if (error.text.contains("PHONE_NUMBER_BANNED")) { needShowInvalidAlert(LoginActivity.this, req.phone_number, true); } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("InvalidCode", R.string.InvalidCode)); } else if (error.text.contains("PHONE_CODE_EXPIRED")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("CodeExpired", R.string.CodeExpired)); } else if (error.text.startsWith("FLOOD_WAIT")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("FloodWait", R.string.FloodWait)); } else if (error.code != -1000) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), error.text); } } } needHideProgress(false); }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagTryDifferentDc | ConnectionsManager.RequestFlagEnableUnauthorized); needShowProgress(reqId); } private boolean numberFilled; public void fillNumber() { if (numberFilled) { return; } try { // TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); if (AndroidUtilities.isSimAvailable()) { boolean allowCall = true; boolean allowReadPhoneNumbers = true; if (Build.VERSION.SDK_INT >= 23) { allowCall = getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { allowReadPhoneNumbers = getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_GRANTED; } if (checkShowPermissions && (!allowCall || !allowReadPhoneNumbers)) { permissionsShowItems.clear(); if (!allowCall) { permissionsShowItems.add(Manifest.permission.READ_PHONE_STATE); } if (!allowReadPhoneNumbers && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { permissionsShowItems.add(Manifest.permission.READ_PHONE_NUMBERS); } if (!permissionsShowItems.isEmpty()) { List callbackPermissionItems = new ArrayList<>(permissionsShowItems); Runnable r = () -> { SharedPreferences preferences = MessagesController.getGlobalMainSettings(); if (preferences.getBoolean("firstloginshow", true) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE)) { preferences.edit().putBoolean("firstloginshow", false).commit(); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTopAnimation(R.raw.incoming_calls, 46, false, Theme.getColor(Theme.key_dialogTopBackground)); builder.setPositiveButton(LocaleController.getString("Continue", R.string.Continue), null); builder.setMessage(LocaleController.getString("AllowFillNumber", R.string.AllowFillNumber)); permissionsShowDialog = showDialog(builder.create(), true, null); needRequestPermissions = true; } else { getParentActivity().requestPermissions(callbackPermissionItems.toArray(new String[0]), BasePermissionsActivity.REQUEST_CODE_CALLS); } }; if (isAnimatingIntro) { animationFinishCallback = r; } else { r.run(); } } return; } } numberFilled = true; if (!newAccount && allowCall && allowReadPhoneNumbers) { codeField.setAlpha(0); phoneField.setAlpha(0); String number = ""; String textToSet = null; boolean ok = false; if (!TextUtils.isEmpty(number)) { if (number.length() > 4) { for (int a = 4; a >= 1; a--) { String sub = number.substring(0, a); CountrySelectActivity.Country country = codesMap.get(sub); if (country != null) { ok = true; textToSet = number.substring(a); codeField.setText(sub); break; } } if (!ok) { textToSet = number.substring(1); codeField.setText(number.substring(0, 1)); } } if (textToSet != null) { phoneField.requestFocus(); phoneField.setText(textToSet); phoneField.setSelection(phoneField.length()); } } if (phoneField.length() > 0) { AnimatorSet set = new AnimatorSet().setDuration(300); set.playTogether(ObjectAnimator.ofFloat(codeField, View.ALPHA, 1f), ObjectAnimator.ofFloat(phoneField, View.ALPHA, 1f)); set.start(); confirmedNumber = true; } else { codeField.setAlpha(1); phoneField.setAlpha(1); } } } } catch (Exception e) { FileLog.e(e); } } @Override public void onShow() { super.onShow(); fillNumber(); if (syncContactsBox != null) { syncContactsBox.setChecked(syncContacts, false); } AndroidUtilities.runOnUIThread(() -> { if (phoneField != null) { if (needRequestPermissions) { codeField.clearFocus(); phoneField.clearFocus(); } else { if (codeField.length() != 0) { phoneField.requestFocus(); if (!numberFilled) { phoneField.setSelection(phoneField.length()); } showKeyboard(phoneField); } else { codeField.requestFocus(); showKeyboard(codeField); } } } }, SHOW_DELAY); } @Override public String getHeaderName() { return LocaleController.getString("YourPhone", R.string.YourPhone); } @Override public void saveStateParams(Bundle bundle) { String code = codeField.getText().toString(); if (code.length() != 0) { bundle.putString("phoneview_code", code); } String phone = phoneField.getText().toString(); if (phone.length() != 0) { bundle.putString("phoneview_phone", phone); } } @Override public void restoreStateParams(Bundle bundle) { String code = bundle.getString("phoneview_code"); if (code != null) { codeField.setText(code); } String phone = bundle.getString("phoneview_phone"); if (phone != null) { phoneField.setText(phone); } } @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.emojiLoaded) { countryButton.getCurrentView().invalidate(); } } } public class LoginActivitySmsView extends SlideView implements NotificationCenter.NotificationCenterDelegate { /* package */ RLottieDrawable hintDrawable; private String phone; private String phoneHash; private String requestPhone; private String emailPhone; private CodeFieldContainer codeFieldContainer; private TextView confirmTextView; private TextView titleTextView; private ImageView blackImageView; private RLottieImageView blueImageView; private TextView timeText; private FrameLayout bottomContainer; private ViewSwitcher errorViewSwitcher; private TextView problemText; private FrameLayout problemFrame; private TextView wrongCode; private Bundle currentParams; private ProgressView progressView; private TextView prefixTextView; private TextView missedCallDescriptionSubtitle; private ImageView missedCallArrowIcon, missedCallPhoneIcon; private RLottieDrawable starsToDotsDrawable; private RLottieDrawable dotsDrawable; private RLottieDrawable dotsToStarsDrawable; private boolean isDotsAnimationVisible; private Timer timeTimer; private Timer codeTimer; private int openTime; private final Object timerSync = new Object(); private int time = 60000; private int codeTime = 15000; private double lastCurrentTime; private double lastCodeTime; private boolean ignoreOnTextChange; private boolean waitingForEvent; private boolean nextPressed; private String lastError = ""; @AuthType private int currentType; @AuthType private int nextType; private String pattern = "*"; private String prefix = ""; private String catchedPhone; private int length; private boolean postedErrorColorTimeout; private Runnable errorColorTimeout = () -> { postedErrorColorTimeout = false; for (int i = 0; i < codeFieldContainer.codeField.length; i++) { codeFieldContainer.codeField[i].animateErrorProgress(0); } if (errorViewSwitcher.getCurrentView() != problemFrame) { errorViewSwitcher.showNext(); } }; public LoginActivitySmsView(Context context, @AuthType int type) { super(context); currentType = type; setOrientation(VERTICAL); confirmTextView = new TextView(context); confirmTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); confirmTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); titleTextView = new TextView(context); titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); titleTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); titleTextView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); String overrideTitle = cancelAccountDeletionMode ? LocaleController.getString(R.string.CancelAccountReset) : null; FrameLayout centerContainer = null; if (currentType == AUTH_TYPE_MISSED_CALL) { titleTextView.setText(overrideTitle != null ? overrideTitle : LocaleController.getString("MissedCallDescriptionTitle", R.string.MissedCallDescriptionTitle)); FrameLayout frameLayout = new FrameLayout(context); missedCallArrowIcon = new ImageView(context); missedCallPhoneIcon = new ImageView(context); frameLayout.addView(missedCallArrowIcon); frameLayout.addView(missedCallPhoneIcon); missedCallArrowIcon.setImageResource(R.drawable.login_arrow1); missedCallPhoneIcon.setImageResource(R.drawable.login_phone1); addView(frameLayout, LayoutHelper.createLinear(64, 64, Gravity.CENTER_HORIZONTAL, 0, 16, 0, 0)); addView(titleTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 8, 0, 0)); missedCallDescriptionSubtitle = new TextView(context); missedCallDescriptionSubtitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); missedCallDescriptionSubtitle.setGravity(Gravity.CENTER_HORIZONTAL); missedCallDescriptionSubtitle.setLineSpacing(AndroidUtilities.dp(2), 1.0f); missedCallDescriptionSubtitle.setText(AndroidUtilities.replaceTags(LocaleController.getString("MissedCallDescriptionSubtitle", R.string.MissedCallDescriptionSubtitle))); addView(missedCallDescriptionSubtitle, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 36, 16, 36, 0)); codeFieldContainer = new CodeFieldContainer(context) { @Override protected void processNextPressed() { onNextPressed(null); } }; LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); prefixTextView = new TextView(context); prefixTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); prefixTextView.setMaxLines(1); prefixTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); prefixTextView.setPadding(0, 0, 0, 0); prefixTextView.setGravity(Gravity.CENTER_VERTICAL); linearLayout.addView(prefixTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL, 0, 0, 4, 0)); linearLayout.addView(codeFieldContainer, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT)); addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 34, Gravity.CENTER_HORIZONTAL, 0, 28, 0, 0)); missedCallDescriptionSubtitle = new TextView(context); missedCallDescriptionSubtitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); missedCallDescriptionSubtitle.setGravity(Gravity.CENTER_HORIZONTAL); missedCallDescriptionSubtitle.setLineSpacing(AndroidUtilities.dp(2), 1.0f); missedCallDescriptionSubtitle.setText(AndroidUtilities.replaceTags(LocaleController.getString("MissedCallDescriptionSubtitle2", R.string.MissedCallDescriptionSubtitle2))); addView(missedCallDescriptionSubtitle, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 36, 28, 36, 12)); } else if (currentType == AUTH_TYPE_FLASH_CALL) { confirmTextView.setGravity(Gravity.CENTER_HORIZONTAL); centerContainer = new FrameLayout(context); addView(centerContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); LinearLayout innerLinearLayout = new LinearLayout(context); innerLinearLayout.setOrientation(VERTICAL); innerLinearLayout.setGravity(Gravity.CENTER_HORIZONTAL); centerContainer.addView(innerLinearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) innerLinearLayout.getLayoutParams(); layoutParams.bottomMargin = AndroidUtilities.isTablet() ? 0 : AndroidUtilities.statusBarHeight; FrameLayout frameLayout = new FrameLayout(context); innerLinearLayout.addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); blueImageView = new RLottieImageView(context); hintDrawable = new RLottieDrawable(R.raw.phone_flash_call, String.valueOf(R.raw.phone_flash_call), AndroidUtilities.dp(64), AndroidUtilities.dp(64), true, null); blueImageView.setAnimation(hintDrawable); frameLayout.addView(blueImageView, LayoutHelper.createFrame(64, 64)); titleTextView.setText(overrideTitle != null ? overrideTitle : LocaleController.getString(R.string.YourCode)); innerLinearLayout.addView(titleTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 16, 0, 0)); innerLinearLayout.addView(confirmTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 8, 0, 0)); } else { confirmTextView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); FrameLayout frameLayout = new FrameLayout(context); addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 16, 0, 0)); int size = currentType == AUTH_TYPE_MESSAGE ? 128 : 64; if (currentType == AUTH_TYPE_MESSAGE) { hintDrawable = new RLottieDrawable(R.raw.code_laptop, String.valueOf(R.raw.code_laptop), AndroidUtilities.dp(size), AndroidUtilities.dp(size), true, null); } else { hintDrawable = new RLottieDrawable(R.raw.sms_incoming_info, String.valueOf(R.raw.sms_incoming_info), AndroidUtilities.dp(size), AndroidUtilities.dp(size), true, null); starsToDotsDrawable = new RLottieDrawable(R.raw.phone_stars_to_dots, String.valueOf(R.raw.phone_stars_to_dots), AndroidUtilities.dp(size), AndroidUtilities.dp(size), true, null); dotsDrawable = new RLottieDrawable(R.raw.phone_dots, String.valueOf(R.raw.phone_dots), AndroidUtilities.dp(size), AndroidUtilities.dp(size), true, null); dotsToStarsDrawable = new RLottieDrawable(R.raw.phone_dots_to_stars, String.valueOf(R.raw.phone_dots_to_stars), AndroidUtilities.dp(size), AndroidUtilities.dp(size), true, null); } blueImageView = new RLottieImageView(context); blueImageView.setAnimation(hintDrawable); if (currentType == AUTH_TYPE_MESSAGE && !AndroidUtilities.isSmallScreen()) { blueImageView.setTranslationY(-AndroidUtilities.dp(24)); } frameLayout.addView(blueImageView, LayoutHelper.createFrame(size, size, Gravity.LEFT | Gravity.TOP, 0, 0, 0, currentType == AUTH_TYPE_MESSAGE && !AndroidUtilities.isSmallScreen() ? -AndroidUtilities.dp(16) : 0)); titleTextView.setText(overrideTitle != null ? overrideTitle : LocaleController.getString(currentType == AUTH_TYPE_MESSAGE ? R.string.SentAppCodeTitle : R.string.SentSmsCodeTitle)); addView(titleTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 18, 0, 0)); addView(confirmTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 17, 0, 0)); } if (currentType != AUTH_TYPE_MISSED_CALL) { codeFieldContainer = new CodeFieldContainer(context) { @Override protected void processNextPressed() { onNextPressed(null); } }; addView(codeFieldContainer, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 42, Gravity.CENTER_HORIZONTAL, 0, 32, 0, 0)); } if (currentType == AUTH_TYPE_FLASH_CALL) { codeFieldContainer.setVisibility(GONE); } problemFrame = new FrameLayout(context); timeText = new TextView(context); timeText.setLineSpacing(AndroidUtilities.dp(2), 1.0f); timeText.setPadding(0, AndroidUtilities.dp(2), 0, AndroidUtilities.dp(10)); timeText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); timeText.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); timeText.setOnClickListener(v-> { if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS || nextType == AUTH_TYPE_MISSED_CALL) { timeText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_MISSED_CALL) { timeText.setText(LocaleController.getString("Calling", R.string.Calling)); } else { timeText.setText(LocaleController.getString("SendingSms", R.string.SendingSms)); } createCodeTimer(); TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); req.phone_number = requestPhone; req.phone_code_hash = phoneHash; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (error != null && error.text != null) { AndroidUtilities.runOnUIThread(() -> lastError = error.text); } }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } else if (nextType == AUTH_TYPE_FLASH_CALL) { AndroidUtilities.setWaitingForSms(false); NotificationCenter.getGlobalInstance().removeObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveSmsCode); waitingForEvent = false; destroyCodeTimer(); resendCode(); } }); problemFrame.addView(timeText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL)); errorViewSwitcher = new ViewSwitcher(context) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(100), MeasureSpec.AT_MOST)); } }; Animation anim = AnimationUtils.loadAnimation(context, R.anim.text_in); anim.setInterpolator(Easings.easeInOutQuad); errorViewSwitcher.setInAnimation(anim); anim = AnimationUtils.loadAnimation(context, R.anim.text_out); anim.setInterpolator(Easings.easeInOutQuad); errorViewSwitcher.setOutAnimation(anim); problemText = new TextView(context); problemText.setLineSpacing(AndroidUtilities.dp(2), 1.0f); problemText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); problemText.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP); problemText.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4)); problemFrame.addView(problemText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); errorViewSwitcher.addView(problemFrame); wrongCode = new TextView(context); wrongCode.setText(LocaleController.getString("WrongCode", R.string.WrongCode)); wrongCode.setLineSpacing(AndroidUtilities.dp(2), 1.0f); wrongCode.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); wrongCode.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP); wrongCode.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4)); errorViewSwitcher.addView(wrongCode); if (currentType == AUTH_TYPE_MESSAGE) { if (nextType == AUTH_TYPE_FLASH_CALL || nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_MISSED_CALL) { problemText.setText(LocaleController.getString("DidNotGetTheCodePhone", R.string.DidNotGetTheCodePhone)); } else { problemText.setText(LocaleController.getString("DidNotGetTheCodeSms", R.string.DidNotGetTheCodeSms)); } } else { problemText.setText(LocaleController.getString("DidNotGetTheCode", R.string.DidNotGetTheCode)); } if (centerContainer == null) { bottomContainer = new FrameLayout(context); bottomContainer.addView(errorViewSwitcher, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 32)); addView(bottomContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); } else { centerContainer.addView(errorViewSwitcher, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 32)); } VerticalPositionAutoAnimator.attach(errorViewSwitcher); problemText.setOnClickListener(v -> { if (nextPressed) { return; } boolean email = nextType == AUTH_TYPE_CALL && currentType == AUTH_TYPE_SMS || nextType == 0; if (!email) { if (radialProgressView.getTag() != null) { return; } resendCode(); } else { new AlertDialog.Builder(context) .setTitle(LocaleController.getString(R.string.RestorePasswordNoEmailTitle)) .setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("DidNotGetTheCodeInfo", R.string.DidNotGetTheCodeInfo, phone))) .setNeutralButton(LocaleController.getString(R.string.DidNotGetTheCodeHelpButton), (dialog, which)->{ try { PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); Intent mailer = new Intent(Intent.ACTION_SENDTO); mailer.setData(Uri.parse("mailto:")); mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"sms@telegram.org"}); mailer.putExtra(Intent.EXTRA_SUBJECT, "Android registration/login issue " + version + " " + emailPhone); mailer.putExtra(Intent.EXTRA_TEXT, "Phone: " + requestPhone + "\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault() + "\nError: " + lastError); getContext().startActivity(Intent.createChooser(mailer, "Send email...")); } catch (Exception e) { needShowAlert(LocaleController.getString(R.string.NekoX), LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); } }) .setPositiveButton(LocaleController.getString(R.string.Close), null) .setNegativeButton(LocaleController.getString(R.string.DidNotGetTheCodeEditNumberButton), (dialog, which)-> setPage(VIEW_PHONE_INPUT, true, null, true)) .show(); } }); } @Override public void updateColors() { confirmTextView.setTextColor(Theme.getColor(cancelAccountDeletionMode ? Theme.key_windowBackgroundWhiteBlackText : Theme.key_windowBackgroundWhiteGrayText6)); confirmTextView.setLinkTextColor(Theme.getColor(Theme.key_chats_actionBackground)); titleTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); if (currentType == AUTH_TYPE_MISSED_CALL) { missedCallDescriptionSubtitle.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); missedCallArrowIcon.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), PorterDuff.Mode.SRC_IN)); missedCallPhoneIcon.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), PorterDuff.Mode.SRC_IN)); prefixTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); } applyLottieColors(hintDrawable); applyLottieColors(starsToDotsDrawable); applyLottieColors(dotsDrawable); applyLottieColors(dotsToStarsDrawable); if (codeFieldContainer != null) { codeFieldContainer.invalidate(); } String timeTextColorTag = (String) timeText.getTag(); if (timeTextColorTag == null) timeTextColorTag = Theme.key_windowBackgroundWhiteGrayText6; timeText.setTextColor(Theme.getColor(timeTextColorTag)); problemText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4)); wrongCode.setTextColor(Theme.getColor(Theme.key_dialogTextRed)); } private void applyLottieColors(RLottieDrawable drawable) { if (drawable != null) { drawable.setLayerColor("Bubble.**", Theme.getColor(Theme.key_chats_actionBackground)); drawable.setLayerColor("Phone.**", Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); drawable.setLayerColor("Note.**", Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); } } @Override public boolean hasCustomKeyboard() { return currentType != AUTH_TYPE_FLASH_CALL; } @Override public void onCancelPressed() { nextPressed = false; } private void resendCode() { final Bundle params = new Bundle(); params.putString("phone", phone); params.putString("ephone", emailPhone); params.putString("phoneFormated", requestPhone); nextPressed = true; TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); req.phone_number = requestPhone; req.phone_code_hash = phoneHash; int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { nextPressed = false; if (error == null) { fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); } else { if (error.text != null) { if (error.text.contains("PHONE_NUMBER_INVALID")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("InvalidCode", R.string.InvalidCode)); } else if (error.text.contains("PHONE_CODE_EXPIRED")) { onBackPressed(true); setPage(VIEW_PHONE_INPUT, true, null, true); needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("CodeExpired", R.string.CodeExpired)); } else if (error.text.startsWith("FLOOD_WAIT")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("FloodWait", R.string.FloodWait)); } else if (error.code != -1000) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text); } } } tryHideProgress(false); }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); tryShowProgress(reqId); } private void tryShowProgress(int reqId) { tryShowProgress(reqId, true); } private void tryShowProgress(int reqId, boolean animate) { if (starsToDotsDrawable != null) { if (isDotsAnimationVisible) { return; } isDotsAnimationVisible = true; if (hintDrawable.getCurrentFrame() != hintDrawable.getFramesCount() - 1) { hintDrawable.setOnAnimationEndListener(()-> AndroidUtilities.runOnUIThread(()-> tryShowProgress(reqId, animate))); return; } starsToDotsDrawable.setOnAnimationEndListener(()-> AndroidUtilities.runOnUIThread(()->{ blueImageView.setAutoRepeat(true); dotsDrawable.setCurrentFrame(0, false); dotsDrawable.setAutoRepeat(1); blueImageView.setAnimation(dotsDrawable); blueImageView.playAnimation(); })); blueImageView.setAutoRepeat(false); starsToDotsDrawable.setCurrentFrame(0, false); blueImageView.setAnimation(starsToDotsDrawable); blueImageView.playAnimation(); return; } needShowProgress(reqId, animate); } private void tryHideProgress(boolean cancel) { tryHideProgress(cancel, true); } private void tryHideProgress(boolean cancel, boolean animate) { if (starsToDotsDrawable != null) { if (!isDotsAnimationVisible) { return; } isDotsAnimationVisible = false; blueImageView.setAutoRepeat(false); dotsDrawable.setAutoRepeat(0); dotsDrawable.setOnFinishCallback(()-> AndroidUtilities.runOnUIThread(()->{ dotsToStarsDrawable.setOnAnimationEndListener(()-> AndroidUtilities.runOnUIThread(()->{ blueImageView.setAutoRepeat(false); blueImageView.setAnimation(hintDrawable); })); blueImageView.setAutoRepeat(false); dotsToStarsDrawable.setCurrentFrame(0, false); blueImageView.setAnimation(dotsToStarsDrawable); blueImageView.playAnimation(); }), dotsDrawable.getFramesCount() - 1); return; } needHideProgress(cancel, animate); } @Override public String getHeaderName() { if (currentType == AUTH_TYPE_FLASH_CALL || currentType == AUTH_TYPE_MISSED_CALL) { return phone; } else { return LocaleController.getString("YourCode", R.string.YourCode); } } @Override public boolean needBackButton() { return true; } @Override public void setParams(Bundle params, boolean restore) { if (params == null) { return; } waitingForEvent = true; if (currentType == AUTH_TYPE_SMS) { AndroidUtilities.setWaitingForSms(true); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didReceiveSmsCode); } else if (currentType == AUTH_TYPE_FLASH_CALL) { AndroidUtilities.setWaitingForCall(true); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didReceiveCall); } currentParams = params; phone = params.getString("phone"); emailPhone = params.getString("ephone"); requestPhone = params.getString("phoneFormated"); phoneHash = params.getString("phoneHash"); time = params.getInt("timeout"); openTime = (int) (System.currentTimeMillis() / 1000); nextType = params.getInt("nextType"); pattern = params.getString("pattern"); prefix = params.getString("prefix"); length = params.getInt("length"); if (length == 0) { length = 5; } codeFieldContainer.setNumbersCount(length, currentType); for (CodeNumberField f : codeFieldContainer.codeField) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { f.setShowSoftInputOnFocusCompat(!(hasCustomKeyboard() && !isCustomKeyboardForceDisabled())); } f.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { if (postedErrorColorTimeout) { removeCallbacks(errorColorTimeout); errorColorTimeout.run(); } } @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) {} }); f.setOnFocusChangeListener((v, hasFocus) -> { if (hasFocus) { keyboardView.setEditText((EditText) v); keyboardView.setDispatchBackWhenEmpty(true); } }); } if (progressView != null) { progressView.setVisibility(nextType != 0 ? VISIBLE : GONE); } if (phone == null) { return; } String number = PhoneFormat.getInstance().format(phone); CharSequence str = ""; if (cancelAccountDeletionMode) { SpannableStringBuilder spanned = new SpannableStringBuilder(AndroidUtilities.replaceTags(LocaleController.formatString("CancelAccountResetInfo2", R.string.CancelAccountResetInfo2, PhoneFormat.getInstance().format("+" + number)))); int startIndex = TextUtils.indexOf(spanned, '*'); int lastIndex = TextUtils.lastIndexOf(spanned, '*'); if (startIndex != -1 && lastIndex != -1 && startIndex != lastIndex) { confirmTextView.setMovementMethod(new AndroidUtilities.LinkMovementMethodMy()); spanned.replace(lastIndex, lastIndex + 1, ""); spanned.replace(startIndex, startIndex + 1, ""); spanned.setSpan(new URLSpanNoUnderline("tg://settings/change_number"), startIndex, lastIndex - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } str = spanned; } else { if (currentType == AUTH_TYPE_MESSAGE) { str = AndroidUtilities.replaceTags(LocaleController.formatString("SentAppCodeWithPhone", R.string.SentAppCodeWithPhone, LocaleController.addNbsp(number))); } else if (currentType == AUTH_TYPE_SMS) { str = AndroidUtilities.replaceTags(LocaleController.formatString("SentSmsCode", R.string.SentSmsCode, LocaleController.addNbsp(number))); } else if (currentType == AUTH_TYPE_FLASH_CALL) { str = AndroidUtilities.replaceTags(LocaleController.formatString("SentCallCode", R.string.SentCallCode, LocaleController.addNbsp(number))); } else if (currentType == AUTH_TYPE_CALL) { str = AndroidUtilities.replaceTags(LocaleController.formatString("SentCallOnly", R.string.SentCallOnly, LocaleController.addNbsp(number))); } } confirmTextView.setText(str); if (currentType != AUTH_TYPE_FLASH_CALL) { showKeyboard(codeFieldContainer.codeField[0]); codeFieldContainer.codeField[0].requestFocus(); } else { AndroidUtilities.hideKeyboard(codeFieldContainer.codeField[0]); } destroyTimer(); destroyCodeTimer(); lastCurrentTime = System.currentTimeMillis(); if (currentType == AUTH_TYPE_MESSAGE) { setProblemTextVisible(true); timeText.setVisibility(GONE); } else if (currentType == AUTH_TYPE_FLASH_CALL && (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS)) { setProblemTextVisible(false); timeText.setVisibility(VISIBLE); if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_MISSED_CALL) { timeText.setText(LocaleController.formatString("CallAvailableIn", R.string.CallAvailableIn, 1, 0)); } else if (nextType == AUTH_TYPE_SMS) { timeText.setText(LocaleController.formatString("SmsAvailableIn", R.string.SmsAvailableIn, 1, 0)); } String callLogNumber = restore ? AndroidUtilities.obtainLoginPhoneCall(pattern) : null; if (callLogNumber != null) { onNextPressed(callLogNumber); } else if (catchedPhone != null) { onNextPressed(catchedPhone); } else { createTimer(); } } else if (currentType == AUTH_TYPE_SMS && (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_FLASH_CALL)) { timeText.setText(LocaleController.formatString("CallAvailableIn", R.string.CallAvailableIn, 2, 0)); setProblemTextVisible(time < 1000); timeText.setVisibility(time < 1000 ? GONE : VISIBLE); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); String hash = preferences.getString("sms_hash", null); String savedCode = null; if (!TextUtils.isEmpty(hash)) { savedCode = preferences.getString("sms_hash_code", null); if (savedCode != null && savedCode.contains(hash + "|")) { savedCode = savedCode.substring(savedCode.indexOf('|') + 1); } else { savedCode = null; } } if (savedCode != null) { codeFieldContainer.setCode(savedCode); onNextPressed(null); } else { createTimer(); } } else if (currentType == AUTH_TYPE_CALL && nextType == AUTH_TYPE_SMS) { timeText.setText(LocaleController.formatString("SmsAvailableIn", R.string.SmsAvailableIn, 2, 0)); setProblemTextVisible(time < 1000); timeText.setVisibility(time < 1000 ? GONE : VISIBLE); createTimer(); } else { timeText.setVisibility(GONE); setProblemTextVisible(false); createCodeTimer(); } if (currentType == AUTH_TYPE_MISSED_CALL) { String pref = prefix; for (int i = 0; i < length; i++) { pref += "0"; } pref = PhoneFormat.getInstance().format("+" + pref); for (int i = 0; i < length; i++) { int index = pref.lastIndexOf("0"); if (index >= 0) { pref = pref.substring(0, index); } } pref = pref.replaceAll("\\)", ""); pref = pref.replaceAll("\\(", ""); prefixTextView.setText(pref); } } private void setProblemTextVisible(boolean visible) { float newAlpha = visible ? 1f : 0f; if (problemText.getAlpha() != newAlpha) { problemText.animate().cancel(); problemText.animate().alpha(newAlpha).setDuration(150).start(); } } private void createCodeTimer() { if (codeTimer != null) { return; } codeTime = 15000; codeTimer = new Timer(); lastCodeTime = System.currentTimeMillis(); codeTimer.schedule(new TimerTask() { @Override public void run() { AndroidUtilities.runOnUIThread(() -> { double currentTime = System.currentTimeMillis(); double diff = currentTime - lastCodeTime; lastCodeTime = currentTime; codeTime -= diff; if (codeTime <= 1000) { setProblemTextVisible(true); timeText.setVisibility(GONE); destroyCodeTimer(); } }); } }, 0, 1000); } private void destroyCodeTimer() { try { synchronized (timerSync) { if (codeTimer != null) { codeTimer.cancel(); codeTimer = null; } } } catch (Exception e) { FileLog.e(e); } } private void createTimer() { if (timeTimer != null) { return; } timeText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); timeText.setTag(R.id.color_key_tag, Theme.key_windowBackgroundWhiteGrayText6); if (progressView != null) { progressView.resetProgressAnimation(); } timeTimer = new Timer(); timeTimer.schedule(new TimerTask() { @Override public void run() { if (timeTimer == null) { return; } AndroidUtilities.runOnUIThread(() -> { double currentTime = System.currentTimeMillis(); double diff = currentTime - lastCurrentTime; lastCurrentTime = currentTime; time -= diff; if (time >= 1000) { int minutes = time / 1000 / 60; int seconds = time / 1000 - minutes * 60; if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_FLASH_CALL || nextType == AUTH_TYPE_MISSED_CALL) { timeText.setText(LocaleController.formatString("CallAvailableIn", R.string.CallAvailableIn, minutes, seconds)); } else if (nextType == AUTH_TYPE_SMS) { timeText.setText(LocaleController.formatString("SmsAvailableIn", R.string.SmsAvailableIn, minutes, seconds)); } if (progressView != null && !progressView.isProgressAnimationRunning()) { progressView.startProgressAnimation(time - 1000L); } } else { destroyTimer(); if (nextType == AUTH_TYPE_FLASH_CALL || nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS || nextType == AUTH_TYPE_MISSED_CALL) { if (nextType == AUTH_TYPE_CALL) { timeText.setText(LocaleController.getString("RequestCallButton", R.string.RequestCallButton)); } else if (nextType == AUTH_TYPE_MISSED_CALL || nextType == AUTH_TYPE_FLASH_CALL) { timeText.setText(LocaleController.getString("RequestMissedCall", R.string.RequestMissedCall)); } else { timeText.setText(LocaleController.getString("RequestSmsButton", R.string.RequestSmsButton)); } timeText.setTextColor(Theme.getColor(Theme.key_chats_actionBackground)); timeText.setTag(R.id.color_key_tag, Theme.key_chats_actionBackground); } } }); } }, 0, 1000); } private void destroyTimer() { timeText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); timeText.setTag(R.id.color_key_tag, Theme.key_windowBackgroundWhiteGrayText6); try { synchronized (timerSync) { if (timeTimer != null) { timeTimer.cancel(); timeTimer = null; } } } catch (Exception e) { FileLog.e(e); } } @Override public void onNextPressed(String code) { if (currentViewNum == AUTH_TYPE_MISSED_CALL) { if (nextPressed) { return; } } else { if (nextPressed || currentViewNum < VIEW_CODE_MESSAGE || currentViewNum > VIEW_CODE_CALL) { return; } } if (code == null) { code = codeFieldContainer.getCode(); } if (TextUtils.isEmpty(code)) { onFieldError(codeFieldContainer, false); return; } if (currentViewNum >= VIEW_CODE_MESSAGE && currentViewNum <= VIEW_CODE_CALL && codeFieldContainer.isFocusSuppressed) { return; } nextPressed = true; if (currentType == AUTH_TYPE_SMS) { AndroidUtilities.setWaitingForSms(false); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); } else if (currentType == AUTH_TYPE_FLASH_CALL) { AndroidUtilities.setWaitingForCall(false); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didReceiveCall); } waitingForEvent = false; if (cancelAccountDeletionMode) { requestPhone = cancelDeletionPhone; final TLRPC.TL_account_confirmPhone req = new TLRPC.TL_account_confirmPhone(); req.phone_code = code; req.phone_code_hash = phoneHash; destroyTimer(); codeFieldContainer.isFocusSuppressed = true; for (CodeNumberField f : codeFieldContainer.codeField) { f.animateFocusedProgress(0); } int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { tryHideProgress(false); nextPressed = false; if (error == null) { animateSuccess(()-> new AlertDialog.Builder(getParentActivity()) .setTitle(LocaleController.getString(R.string.CancelLinkSuccessTitle)) .setMessage(LocaleController.formatString("CancelLinkSuccess", R.string.CancelLinkSuccess, PhoneFormat.getInstance().format("+" + phone))) .setPositiveButton(LocaleController.getString(R.string.Close), null) .setOnDismissListener(dialog -> finishFragment()) .show()); } else { lastError = error.text; if (currentType == AUTH_TYPE_FLASH_CALL && (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS) || currentType == AUTH_TYPE_SMS && (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_FLASH_CALL) || currentType == AUTH_TYPE_CALL && nextType == AUTH_TYPE_SMS) { createTimer(); } if (currentType == AUTH_TYPE_SMS) { AndroidUtilities.setWaitingForSms(true); NotificationCenter.getGlobalInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveSmsCode); } else if (currentType == AUTH_TYPE_FLASH_CALL) { AndroidUtilities.setWaitingForCall(true); NotificationCenter.getGlobalInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveCall); } waitingForEvent = true; if (currentType != AUTH_TYPE_FLASH_CALL) { AlertsCreator.processError(currentAccount, error, LoginActivity.this, req); } if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { shakeWrongCode(); } else if (error.text.contains("PHONE_CODE_EXPIRED")) { onBackPressed(true); setPage(VIEW_PHONE_INPUT, true, null, true); } } }), ConnectionsManager.RequestFlagFailOnServerErrors); tryShowProgress(reqId); } else { final TLRPC.TL_auth_signIn req = new TLRPC.TL_auth_signIn(); req.phone_number = requestPhone; req.phone_code = code; req.phone_code_hash = phoneHash; destroyTimer(); codeFieldContainer.isFocusSuppressed = true; for (CodeNumberField f : codeFieldContainer.codeField) { f.animateFocusedProgress(0); } int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { tryHideProgress(false, true); boolean ok = false; if (error == null) { nextPressed = false; ok = true; showDoneButton(false, true); destroyTimer(); destroyCodeTimer(); if (response instanceof TLRPC.TL_auth_authorizationSignUpRequired) { TLRPC.TL_auth_authorizationSignUpRequired authorization = (TLRPC.TL_auth_authorizationSignUpRequired) response; if (authorization.terms_of_service != null) { currentTermsOfService = authorization.terms_of_service; } Bundle params = new Bundle(); params.putString("phoneFormated", requestPhone); params.putString("phoneHash", phoneHash); params.putString("code", req.phone_code); animateSuccess(() -> setPage(VIEW_REGISTER, true, params, false)); } else { animateSuccess(() -> onAuthSuccess((TLRPC.TL_auth_authorization) response)); } } else { lastError = error.text; if (error.text.contains("SESSION_PASSWORD_NEEDED")) { ok = true; TLRPC.TL_account_getPassword req2 = new TLRPC.TL_account_getPassword(); ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { nextPressed = false; showDoneButton(false, true); if (error1 == null) { TLRPC.TL_account_password password = (TLRPC.TL_account_password) response1; if (!TwoStepVerificationActivity.canHandleCurrentPassword(password, true)) { AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); return; } Bundle bundle = new Bundle(); SerializedData data = new SerializedData(password.getObjectSize()); password.serializeToStream(data); bundle.putString("password", Utilities.bytesToHex(data.toByteArray())); bundle.putString("phoneFormated", requestPhone); bundle.putString("phoneHash", phoneHash); bundle.putString("code", req.phone_code); animateSuccess(() -> setPage(VIEW_PASSWORD, true, bundle, false)); } else { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), error1.text); } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); destroyTimer(); destroyCodeTimer(); } else { nextPressed = false; showDoneButton(false, true); if (currentType == AUTH_TYPE_FLASH_CALL && (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS) || currentType == AUTH_TYPE_SMS && (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_FLASH_CALL) || currentType == AUTH_TYPE_CALL && nextType == AUTH_TYPE_SMS) { createTimer(); } if (currentType == AUTH_TYPE_SMS) { AndroidUtilities.setWaitingForSms(true); NotificationCenter.getGlobalInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveSmsCode); } else if (currentType == AUTH_TYPE_FLASH_CALL) { AndroidUtilities.setWaitingForCall(true); NotificationCenter.getGlobalInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveCall); } waitingForEvent = true; if (currentType != AUTH_TYPE_FLASH_CALL) { boolean isWrongCode = false; if (error.text.contains("PHONE_NUMBER_INVALID")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { shakeWrongCode(); isWrongCode = true; } else if (error.text.contains("PHONE_CODE_EXPIRED")) { onBackPressed(true); setPage(VIEW_PHONE_INPUT, true, null, true); needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("CodeExpired", R.string.CodeExpired)); } else if (error.text.startsWith("FLOOD_WAIT")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("FloodWait", R.string.FloodWait)); } else { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text); } if (!isWrongCode) { for (int a = 0; a < codeFieldContainer.codeField.length; a++) { codeFieldContainer.codeField[a].setText(""); } codeFieldContainer.isFocusSuppressed = false; codeFieldContainer.codeField[0].requestFocus(); } } } } if (ok) { if (currentType == AUTH_TYPE_FLASH_CALL) { AndroidUtilities.endIncomingCall(); } } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); tryShowProgress(reqId, true); showDoneButton(true, true); } } private void animateSuccess(Runnable callback) { for (int i = 0; i < codeFieldContainer.codeField.length; i++) { int finalI = i; codeFieldContainer.postDelayed(()-> codeFieldContainer.codeField[finalI].animateSuccessProgress(1f), i * 75L); } codeFieldContainer.postDelayed(()->{ for (int i = 0; i < codeFieldContainer.codeField.length; i++) { codeFieldContainer.codeField[i].animateSuccessProgress(0f); } callback.run(); codeFieldContainer.isFocusSuppressed = false; }, codeFieldContainer.codeField.length * 75L + 400L); } private void shakeWrongCode() { try { codeFieldContainer.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignore) {} for (int a = 0; a < codeFieldContainer.codeField.length; a++) { codeFieldContainer.codeField[a].setText(""); codeFieldContainer.codeField[a].animateErrorProgress(1f); } if (errorViewSwitcher.getCurrentView() == problemFrame) { errorViewSwitcher.showNext(); } codeFieldContainer.codeField[0].requestFocus(); AndroidUtilities.shakeViewSpring(codeFieldContainer, currentType == AUTH_TYPE_MISSED_CALL ? 3.5f : 10f, () -> { postDelayed(()-> { codeFieldContainer.isFocusSuppressed = false; codeFieldContainer.codeField[0].requestFocus(); for (int a = 0; a < codeFieldContainer.codeField.length; a++) { codeFieldContainer.codeField[a].animateErrorProgress(0f); } }, 150); }); removeCallbacks(errorColorTimeout); postDelayed(errorColorTimeout, 5000); postedErrorColorTimeout = true; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); removeCallbacks(errorColorTimeout); } @Override public boolean onBackPressed(boolean force) { if (cancelAccountDeletionMode) { finishFragment(); return false; } if (!force) { showDialog(new AlertDialog.Builder(getParentActivity()) .setTitle(LocaleController.getString(R.string.EditNumber)) .setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("EditNumberInfo", R.string.EditNumberInfo, phone))) .setPositiveButton(LocaleController.getString(R.string.Close), null) .setNegativeButton(LocaleController.getString(R.string.Edit), (dialogInterface, i) -> { onBackPressed(true); setPage(VIEW_PHONE_INPUT, true, null, true); }) .create()); return false; } nextPressed = false; tryHideProgress(true); TLRPC.TL_auth_cancelCode req = new TLRPC.TL_auth_cancelCode(); req.phone_number = requestPhone; req.phone_code_hash = phoneHash; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); destroyTimer(); destroyCodeTimer(); currentParams = null; if (currentType == AUTH_TYPE_SMS) { AndroidUtilities.setWaitingForSms(false); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); } else if (currentType == AUTH_TYPE_FLASH_CALL) { AndroidUtilities.setWaitingForCall(false); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didReceiveCall); } waitingForEvent = false; return true; } @Override public void onDestroyActivity() { super.onDestroyActivity(); if (currentType == AUTH_TYPE_SMS) { AndroidUtilities.setWaitingForSms(false); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); } else if (currentType == AUTH_TYPE_FLASH_CALL) { AndroidUtilities.setWaitingForCall(false); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didReceiveCall); } waitingForEvent = false; destroyTimer(); destroyCodeTimer(); } @Override public void onShow() { super.onShow(); if (hintDrawable != null) { hintDrawable.setCurrentFrame(0); } AndroidUtilities.runOnUIThread(() -> { if (currentType != AUTH_TYPE_FLASH_CALL && codeFieldContainer.codeField != null) { for (int a = codeFieldContainer.codeField.length - 1; a >= 0; a--) { if (a == 0 || codeFieldContainer.codeField[a].length() != 0) { codeFieldContainer.codeField[a].requestFocus(); codeFieldContainer.codeField[a].setSelection(codeFieldContainer.codeField[a].length()); showKeyboard(codeFieldContainer.codeField[a]); break; } } } if (hintDrawable != null) { hintDrawable.start(); } }, SHOW_DELAY); } @Override public void didReceivedNotification(int id, int account, Object... args) { if (!waitingForEvent || codeFieldContainer.codeField == null) { return; } if (id == NotificationCenter.didReceiveSmsCode) { codeFieldContainer.setText("" + args[0]); onNextPressed(null); } else if (id == NotificationCenter.didReceiveCall) { String num = "" + args[0]; if (!AndroidUtilities.checkPhonePattern(pattern, num)) { return; } if (!pattern.equals("*")) { catchedPhone = num; AndroidUtilities.endIncomingCall(); } onNextPressed(num); } } @Override public void saveStateParams(Bundle bundle) { String code = codeFieldContainer.getCode(); if (code.length() != 0) { bundle.putString("smsview_code_" + currentType, code); } if (catchedPhone != null) { bundle.putString("catchedPhone", catchedPhone); } if (currentParams != null) { bundle.putBundle("smsview_params_" + currentType, currentParams); } if (time != 0) { bundle.putInt("time", time); } if (openTime != 0) { bundle.putInt("open", openTime); } } @Override public void restoreStateParams(Bundle bundle) { currentParams = bundle.getBundle("smsview_params_" + currentType); if (currentParams != null) { setParams(currentParams, true); } String catched = bundle.getString("catchedPhone"); if (catched != null) { catchedPhone = catched; } String code = bundle.getString("smsview_code_" + currentType); if (code != null && codeFieldContainer.codeField != null) { codeFieldContainer.setText(code); } int t = bundle.getInt("time"); if (t != 0) { time = t; } int t2 = bundle.getInt("open"); if (t2 != 0) { openTime = t2; } } } public class LoginActivityPasswordView extends SlideView { private EditTextBoldCursor codeField; private TextView confirmTextView; private TextView cancelButton; private TextView titleView; private RLottieImageView lockImageView; private Bundle currentParams; private boolean nextPressed; private TLRPC.TL_account_password currentPassword; private String passwordString; private String requestPhone; private String phoneHash; private String phoneCode; private OutlineTextContainerView outlineCodeField; public LoginActivityPasswordView(Context context) { super(context); setOrientation(VERTICAL); FrameLayout lockFrameLayout = new FrameLayout(context); lockImageView = new RLottieImageView(context); lockImageView.setAnimation(R.raw.tsv_setup_intro, 120, 120); lockImageView.setAutoRepeat(false); lockFrameLayout.addView(lockImageView, LayoutHelper.createFrame(120, 120, Gravity.CENTER_HORIZONTAL)); lockFrameLayout.setVisibility(AndroidUtilities.isSmallScreen() || (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y && !AndroidUtilities.isTablet()) ? GONE : VISIBLE); addView(lockFrameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); titleView = new TextView(context); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleView.setText(LocaleController.getString(R.string.YourPasswordHeader)); titleView.setGravity(Gravity.CENTER); titleView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 32, 16, 32, 0)); confirmTextView = new TextView(context); confirmTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); confirmTextView.setGravity(Gravity.CENTER_HORIZONTAL); confirmTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); confirmTextView.setText(LocaleController.getString(R.string.LoginPasswordTextShort)); addView(confirmTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12, 8, 12, 0)); outlineCodeField = new OutlineTextContainerView(context); outlineCodeField.setText(LocaleController.getString(R.string.EnterPassword)); codeField = new EditTextAutoFill(context); codeField.setCursorSize(AndroidUtilities.dp(20)); codeField.setCursorWidth(1.5f); codeField.setBackground(null); codeField.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI); codeField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); codeField.setMaxLines(1); int padding = AndroidUtilities.dp(16); codeField.setPadding(padding, padding, padding, padding); codeField.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); codeField.setTransformationMethod(PasswordTransformationMethod.getInstance()); codeField.setTypeface(Typeface.DEFAULT); codeField.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); codeField.setOnFocusChangeListener((v, hasFocus) -> outlineCodeField.animateSelection(hasFocus ? 1f : 0f)); outlineCodeField.attachEditText(codeField); outlineCodeField.addView(codeField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); codeField.setOnEditorActionListener((textView, i, keyEvent) -> { if (i == EditorInfo.IME_ACTION_NEXT) { onNextPressed(null); return true; } return false; }); addView(outlineCodeField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 16, 32, 16, 0)); cancelButton = new TextView(context); cancelButton.setGravity(Gravity.CENTER | Gravity.LEFT); cancelButton.setText(LocaleController.getString("ForgotPassword", R.string.ForgotPassword)); cancelButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); cancelButton.setLineSpacing(AndroidUtilities.dp(2), 1.0f); cancelButton.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); FrameLayout bottomContainer = new FrameLayout(context); bottomContainer.addView(cancelButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, (Build.VERSION.SDK_INT >= 21 ? 56 : 60), Gravity.BOTTOM, 0, 0, 0, 32)); addView(bottomContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); VerticalPositionAutoAnimator.attach(cancelButton); cancelButton.setOnClickListener(view -> { if (radialProgressView.getTag() != null) { return; } if (currentPassword.has_recovery) { needShowProgress(0); TLRPC.TL_auth_requestPasswordRecovery req = new TLRPC.TL_auth_requestPasswordRecovery(); ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { needHideProgress(false); if (error == null) { final TLRPC.TL_auth_passwordRecovery res = (TLRPC.TL_auth_passwordRecovery) response; AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); String rawPattern = res.email_pattern; SpannableStringBuilder emailPattern = SpannableStringBuilder.valueOf(rawPattern); int startIndex = rawPattern.indexOf('*'), endIndex = rawPattern.lastIndexOf('*'); if (startIndex != endIndex && startIndex != -1 && endIndex != -1) { TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun(); run.flags |= TextStyleSpan.FLAG_STYLE_SPOILER; run.start = startIndex; run.end = endIndex + 1; emailPattern.setSpan(new TextStyleSpan(run), startIndex, endIndex + 1, 0); } builder.setMessage(AndroidUtilities.formatSpannable(LocaleController.getString(R.string.RestoreEmailSent), emailPattern)); builder.setTitle(LocaleController.getString("RestoreEmailSentTitle", R.string.RestoreEmailSentTitle)); builder.setPositiveButton(LocaleController.getString(R.string.Continue), (dialogInterface, i) -> { Bundle bundle = new Bundle(); bundle.putString("email_unconfirmed_pattern", res.email_pattern); bundle.putString("password", passwordString); bundle.putString("requestPhone", requestPhone); bundle.putString("phoneHash", phoneHash); bundle.putString("phoneCode", phoneCode); setPage(VIEW_RECOVER, true, bundle, false); }); Dialog dialog = showDialog(builder.create()); if (dialog != null) { dialog.setCanceledOnTouchOutside(false); dialog.setCancelable(false); } } else { if (error.text.startsWith("FLOOD_WAIT")) { int time = Utilities.parseInt(error.text); String timeString; if (time < 60) { timeString = LocaleController.formatPluralString("Seconds", time); } else { timeString = LocaleController.formatPluralString("Minutes", time / 60); } needShowAlert(LocaleController.getString(R.string.WrongCodeTitle), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); } else { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), error.text); } } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } else { AndroidUtilities.hideKeyboard(codeField); new AlertDialog.Builder(context) .setTitle(LocaleController.getString(R.string.RestorePasswordNoEmailTitle)) .setMessage(LocaleController.getString(R.string.RestorePasswordNoEmailText)) .setPositiveButton(LocaleController.getString(R.string.Close), null) .setNegativeButton(LocaleController.getString(R.string.ResetAccount), (dialog, which) -> tryResetAccount(requestPhone, phoneHash, phoneCode)) .show(); } }); } @Override public void updateColors() { titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); confirmTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); codeField.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); codeField.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); codeField.setHintTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText)); cancelButton.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4)); outlineCodeField.updateColor(); } @Override public String getHeaderName() { return LocaleController.getString("LoginPassword", R.string.LoginPassword); } @Override public void onCancelPressed() { nextPressed = false; } @Override public void setParams(Bundle params, boolean restore) { if (params == null) { return; } if (params.isEmpty()) { AndroidUtilities.hideKeyboard(codeField); return; } codeField.setText(""); currentParams = params; passwordString = currentParams.getString("password"); if (passwordString != null) { SerializedData data = new SerializedData(Utilities.hexToBytes(passwordString)); currentPassword = TLRPC.TL_account_password.TLdeserialize(data, data.readInt32(false), false); } requestPhone = params.getString("phoneFormated"); phoneHash = params.getString("phoneHash"); phoneCode = params.getString("code"); if (currentPassword != null && !TextUtils.isEmpty(currentPassword.hint)) { codeField.setHint(currentPassword.hint); } else { codeField.setHint(null); } } private void onPasscodeError(boolean clear) { if (getParentActivity() == null) { return; } if (clear) { codeField.setText(""); } onFieldError(outlineCodeField, true); } @Override public void onNextPressed(String code) { if (nextPressed) { return; } String oldPassword = codeField.getText().toString(); if (oldPassword.length() == 0) { onPasscodeError(false); return; } nextPressed = true; needShowProgress(0); Utilities.globalQueue.postRunnable(() -> { final byte[] x_bytes; TLRPC.PasswordKdfAlgo current_algo = currentPassword.current_algo; if (current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { byte[] passwordBytes = AndroidUtilities.getStringBytes(oldPassword); TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) current_algo; x_bytes = SRPHelper.getX(passwordBytes, algo); } else { x_bytes = null; } final TLRPC.TL_auth_checkPassword req = new TLRPC.TL_auth_checkPassword(); RequestDelegate requestDelegate = (response, error) -> AndroidUtilities.runOnUIThread(() -> { nextPressed = false; if (error != null && "SRP_ID_INVALID".equals(error.text)) { TLRPC.TL_account_getPassword getPasswordReq = new TLRPC.TL_account_getPassword(); ConnectionsManager.getInstance(currentAccount).sendRequest(getPasswordReq, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { if (error2 == null) { currentPassword = (TLRPC.TL_account_password) response2; onNextPressed(null); } }), ConnectionsManager.RequestFlagWithoutLogin); return; } if (response instanceof TLRPC.TL_auth_authorization) { showDoneButton(false, true); postDelayed(() -> { needHideProgress(false, false); AndroidUtilities.hideKeyboard(codeField); onAuthSuccess((TLRPC.TL_auth_authorization) response); }, 150); } else { needHideProgress(false); if (error.text.equals("PASSWORD_HASH_INVALID")) { onPasscodeError(true); } else if (error.text.startsWith("FLOOD_WAIT")) { int time = Utilities.parseInt(error.text); String timeString; if (time < 60) { timeString = LocaleController.formatPluralString("Seconds", time); } else { timeString = LocaleController.formatPluralString("Minutes", time / 60); } needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); } else { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), error.text); } } }); if (current_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { req.password = SRPHelper.startCheck(x_bytes, currentPassword.srp_id, currentPassword.srp_B, (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) current_algo); if (req.password == null) { TLRPC.TL_error error = new TLRPC.TL_error(); error.text = "PASSWORD_HASH_INVALID"; requestDelegate.run(null, error); return; } ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } }); } @Override public boolean needBackButton() { return true; } @Override public boolean onBackPressed(boolean force) { nextPressed = false; needHideProgress(true); currentParams = null; return true; } @Override public void onShow() { super.onShow(); AndroidUtilities.runOnUIThread(() -> { if (codeField != null) { codeField.requestFocus(); codeField.setSelection(codeField.length()); showKeyboard(codeField); lockImageView.getAnimatedDrawable().setCurrentFrame(0, false); lockImageView.playAnimation(); } }, SHOW_DELAY); } @Override public void saveStateParams(Bundle bundle) { String code = codeField.getText().toString(); if (code.length() != 0) { bundle.putString("passview_code", code); } if (currentParams != null) { bundle.putBundle("passview_params", currentParams); } } @Override public void restoreStateParams(Bundle bundle) { currentParams = bundle.getBundle("passview_params"); if (currentParams != null) { setParams(currentParams, true); } String code = bundle.getString("passview_code"); if (code != null) { codeField.setText(code); } } } public class LoginActivityResetWaitView extends SlideView { private RLottieImageView waitImageView; private TextView titleView; private TextView confirmTextView; private TextView resetAccountButton; private TextView resetAccountTime; private TextView resetAccountText; private Runnable timeRunnable; private Bundle currentParams; private String requestPhone; private String phoneHash; private String phoneCode; private int startTime; private int waitTime; private Boolean wasResetButtonActive; public LoginActivityResetWaitView(Context context) { super(context); setOrientation(VERTICAL); LinearLayout innerLinearLayout = new LinearLayout(context); innerLinearLayout.setOrientation(VERTICAL); innerLinearLayout.setGravity(Gravity.CENTER); FrameLayout waitFrameLayout = new FrameLayout(context); waitImageView = new RLottieImageView(context); waitImageView.setAutoRepeat(true); waitImageView.setAnimation(R.raw.sandclock, 120, 120); waitFrameLayout.addView(waitImageView, LayoutHelper.createFrame(120, 120, Gravity.CENTER_HORIZONTAL)); waitFrameLayout.setVisibility(AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y && !AndroidUtilities.isTablet() ? GONE : VISIBLE); innerLinearLayout.addView(waitFrameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); titleView = new TextView(context); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleView.setText(LocaleController.getString(R.string.ResetAccount)); titleView.setGravity(Gravity.CENTER); titleView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); innerLinearLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 32, 16, 32, 0)); confirmTextView = new TextView(context); confirmTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); confirmTextView.setGravity(Gravity.CENTER_HORIZONTAL); confirmTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); innerLinearLayout.addView(confirmTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12, 8, 12, 0)); addView(innerLinearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); resetAccountText = new TextView(context); resetAccountText.setGravity(Gravity.CENTER_HORIZONTAL); resetAccountText.setText(LocaleController.getString("ResetAccountStatus", R.string.ResetAccountStatus)); resetAccountText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); resetAccountText.setLineSpacing(AndroidUtilities.dp(2), 1.0f); addView(resetAccountText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 24, 0, 0)); resetAccountTime = new TextView(context); resetAccountTime.setGravity(Gravity.CENTER_HORIZONTAL); resetAccountTime.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); resetAccountTime.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); resetAccountTime.setLineSpacing(AndroidUtilities.dp(2), 1.0f); addView(resetAccountTime, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 8, 0, 0)); resetAccountButton = new TextView(context); resetAccountButton.setGravity(Gravity.CENTER); resetAccountButton.setText(LocaleController.getString(R.string.ResetAccount)); resetAccountButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); resetAccountButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); resetAccountButton.setLineSpacing(AndroidUtilities.dp(2), 1.0f); resetAccountButton.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); resetAccountButton.setTextColor(Color.WHITE); addView(resetAccountButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50, Gravity.CENTER_HORIZONTAL, 16, 32, 16, 48)); resetAccountButton.setOnClickListener(view -> { if (radialProgressView.getTag() != null) { return; } showDialog(new AlertDialog.Builder(getParentActivity()) .setTitle(LocaleController.getString("ResetMyAccountWarning", R.string.ResetMyAccountWarning)) .setMessage(LocaleController.getString("ResetMyAccountWarningText", R.string.ResetMyAccountWarningText)) .setPositiveButton(LocaleController.getString("ResetMyAccountWarningReset", R.string.ResetMyAccountWarningReset), (dialogInterface, i) -> { needShowProgress(0); TLRPC.TL_account_deleteAccount req = new TLRPC.TL_account_deleteAccount(); req.reason = "Forgot password"; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { needHideProgress(false); if (error == null) { if (requestPhone == null || phoneHash == null || phoneCode == null) { setPage(VIEW_PHONE_INPUT, true, null, true); return; } Bundle params = new Bundle(); params.putString("phoneFormated", requestPhone); params.putString("phoneHash", phoneHash); params.putString("code", phoneCode); setPage(VIEW_REGISTER, true, params, false); } else { if (error.text.equals("2FA_RECENT_CONFIRM")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("ResetAccountCancelledAlert", R.string.ResetAccountCancelledAlert)); } else { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), error.text); } } }), ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); }) .setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null).create()); }); } @Override public void updateColors() { titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); confirmTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); resetAccountText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); resetAccountTime.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); resetAccountButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), Theme.getColor(Theme.key_changephoneinfo_image2), Theme.getColor(Theme.key_chats_actionPressedBackground))); } @Override public String getHeaderName() { return LocaleController.getString("ResetAccount", R.string.ResetAccount); } private void updateTimeText() { int timeLeft = Math.max(0, waitTime - (ConnectionsManager.getInstance(currentAccount).getCurrentTime() - startTime)); int days = timeLeft / 86400; int daysRounded = (int) Math.round(timeLeft / (float) 86400); int hours = timeLeft / 3600; int minutes = (timeLeft / 60) % 60; int seconds = timeLeft % 60; if (days >= 2) { resetAccountTime.setText(LocaleController.formatPluralString("Days", daysRounded)); } else { resetAccountTime.setText(String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, seconds)); } boolean isResetButtonActive = timeLeft == 0; if (wasResetButtonActive == null || wasResetButtonActive != isResetButtonActive) { if (!isResetButtonActive) { waitImageView.setAutoRepeat(true); if (!waitImageView.isPlaying()) { waitImageView.playAnimation(); } } else { waitImageView.getAnimatedDrawable().setAutoRepeat(0); } resetAccountTime.setVisibility(isResetButtonActive ? INVISIBLE : VISIBLE); resetAccountText.setVisibility(isResetButtonActive ? INVISIBLE : VISIBLE); resetAccountButton.setVisibility(isResetButtonActive ? VISIBLE : INVISIBLE); wasResetButtonActive = isResetButtonActive; } } @Override public void setParams(Bundle params, boolean restore) { if (params == null) { return; } currentParams = params; requestPhone = params.getString("phoneFormated"); phoneHash = params.getString("phoneHash"); phoneCode = params.getString("code"); startTime = params.getInt("startTime"); waitTime = params.getInt("waitTime"); confirmTextView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("ResetAccountInfo", R.string.ResetAccountInfo, LocaleController.addNbsp(PhoneFormat.getInstance().format("+" + requestPhone))))); updateTimeText(); timeRunnable = new Runnable() { @Override public void run() { if (timeRunnable != this) { return; } updateTimeText(); AndroidUtilities.runOnUIThread(timeRunnable, 1000); } }; AndroidUtilities.runOnUIThread(timeRunnable, 1000); } @Override public boolean needBackButton() { return true; } @Override public boolean onBackPressed(boolean force) { needHideProgress(true); AndroidUtilities.cancelRunOnUIThread(timeRunnable); timeRunnable = null; currentParams = null; return true; } @Override public void saveStateParams(Bundle bundle) { if (currentParams != null) { bundle.putBundle("resetview_params", currentParams); } } @Override public void restoreStateParams(Bundle bundle) { currentParams = bundle.getBundle("resetview_params"); if (currentParams != null) { setParams(currentParams, true); } } } public class LoginActivityRecoverView extends SlideView { private CodeFieldContainer codeFieldContainer; private TextView titleView; private TextView confirmTextView; private TextView troubleButton; private RLottieImageView inboxImageView; private Bundle currentParams; private String passwordString; private boolean nextPressed; private String requestPhone, phoneHash, phoneCode; private boolean postedErrorColorTimeout; private Runnable errorColorTimeout = () -> { postedErrorColorTimeout = false; for (int i = 0; i < codeFieldContainer.codeField.length; i++) { codeFieldContainer.codeField[i].animateErrorProgress(0); } }; public LoginActivityRecoverView(Context context) { super(context); setOrientation(VERTICAL); FrameLayout inboxFrameLayout = new FrameLayout(context); inboxImageView = new RLottieImageView(context); inboxImageView.setAnimation(R.raw.tsv_setup_mail, 120, 120); inboxImageView.setAutoRepeat(false); inboxFrameLayout.addView(inboxImageView, LayoutHelper.createFrame(120, 120, Gravity.CENTER_HORIZONTAL)); inboxFrameLayout.setVisibility(AndroidUtilities.isSmallScreen() || (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y && !AndroidUtilities.isTablet()) ? GONE : VISIBLE); addView(inboxFrameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); titleView = new TextView(context); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleView.setText(LocaleController.getString(R.string.EnterCode)); titleView.setGravity(Gravity.CENTER); titleView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 32, 16, 32, 0)); confirmTextView = new TextView(context); confirmTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); confirmTextView.setGravity(Gravity.CENTER); confirmTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); confirmTextView.setText(LocaleController.getString(R.string.RestoreEmailSentInfo)); addView(confirmTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 12, 8, 12, 0)); codeFieldContainer = new CodeFieldContainer(context) { @Override protected void processNextPressed() { onNextPressed(null); } }; codeFieldContainer.setNumbersCount(6, AUTH_TYPE_MESSAGE); for (CodeNumberField f : codeFieldContainer.codeField) { f.setShowSoftInputOnFocusCompat(!(hasCustomKeyboard() && !isCustomKeyboardForceDisabled())); f.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { if (postedErrorColorTimeout) { removeCallbacks(errorColorTimeout); errorColorTimeout.run(); } } @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) {} }); f.setOnFocusChangeListener((v, hasFocus) -> { if (hasFocus) { keyboardView.setEditText((EditText) v); keyboardView.setDispatchBackWhenEmpty(true); } }); } addView(codeFieldContainer, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 42, Gravity.CENTER_HORIZONTAL, 0, 32, 0, 0)); troubleButton = new SpoilersTextView(context); troubleButton.setGravity(Gravity.CENTER); troubleButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); troubleButton.setLineSpacing(AndroidUtilities.dp(2), 1.0f); troubleButton.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(16), AndroidUtilities.dp(16), AndroidUtilities.dp(16)); troubleButton.setMaxLines(2); troubleButton.setOnClickListener(view -> { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()) .setTitle(LocaleController.getString("RestorePasswordNoEmailTitle", R.string.RestorePasswordNoEmailTitle)) .setMessage(LocaleController.getString("RestoreEmailTroubleText", R.string.RestoreEmailTroubleText)) .setPositiveButton(LocaleController.getString(R.string.OK), (dialogInterface, i) -> setPage(VIEW_PASSWORD, true, new Bundle(), true)) .setNegativeButton(LocaleController.getString(R.string.ResetAccount), (dialog, which) -> tryResetAccount(requestPhone, phoneHash, phoneCode)); Dialog dialog = showDialog(builder.create()); if (dialog != null) { dialog.setCanceledOnTouchOutside(false); dialog.setCancelable(false); } }); FrameLayout bottomContainer = new FrameLayout(context); bottomContainer.addView(troubleButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 0, 0, 0, 32)); addView(bottomContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 0, 1f)); VerticalPositionAutoAnimator.attach(troubleButton); } @Override public void updateColors() { titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); confirmTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); troubleButton.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4)); codeFieldContainer.invalidate(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); removeCallbacks(errorColorTimeout); } @Override public boolean hasCustomKeyboard() { return true; } @Override public boolean needBackButton() { return true; } @Override public void onCancelPressed() { nextPressed = false; } @Override public String getHeaderName() { return LocaleController.getString("LoginPassword", R.string.LoginPassword); } @Override public void setParams(Bundle params, boolean restore) { if (params == null) { return; } codeFieldContainer.setText(""); currentParams = params; passwordString = currentParams.getString("password"); requestPhone = currentParams.getString("requestPhone"); phoneHash = currentParams.getString("phoneHash"); phoneCode = currentParams.getString("phoneCode"); String rawPattern = currentParams.getString("email_unconfirmed_pattern"); SpannableStringBuilder unconfirmedPattern = SpannableStringBuilder.valueOf(rawPattern); int startIndex = rawPattern.indexOf('*'), endIndex = rawPattern.lastIndexOf('*'); if (startIndex != endIndex && startIndex != -1 && endIndex != -1) { TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun(); run.flags |= TextStyleSpan.FLAG_STYLE_SPOILER; run.start = startIndex; run.end = endIndex + 1; unconfirmedPattern.setSpan(new TextStyleSpan(run), startIndex, endIndex + 1, 0); } troubleButton.setText(AndroidUtilities.formatSpannable(LocaleController.getString(R.string.RestoreEmailNoAccess), unconfirmedPattern)); showKeyboard(codeFieldContainer); codeFieldContainer.requestFocus(); } private void onPasscodeError(boolean clear) { if (getParentActivity() == null) { return; } try { codeFieldContainer.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignore) {} if (clear) { for (CodeNumberField f : codeFieldContainer.codeField) { f.setText(""); } } for (CodeNumberField f : codeFieldContainer.codeField) { f.animateErrorProgress(1f); } codeFieldContainer.codeField[0].requestFocus(); AndroidUtilities.shakeViewSpring(codeFieldContainer, () -> { postDelayed(()-> { codeFieldContainer.isFocusSuppressed = false; codeFieldContainer.codeField[0].requestFocus(); for (int a = 0; a < codeFieldContainer.codeField.length; a++) { codeFieldContainer.codeField[a].animateErrorProgress(0f); } }, 150); removeCallbacks(errorColorTimeout); postDelayed(errorColorTimeout, 3000); postedErrorColorTimeout = true; }); } @Override public void onNextPressed(String code) { if (nextPressed) { return; } codeFieldContainer.isFocusSuppressed = true; for (CodeNumberField f : codeFieldContainer.codeField) { f.animateFocusedProgress(0); } code = codeFieldContainer.getCode(); if (code.length() == 0) { onPasscodeError(false); return; } nextPressed = true; needShowProgress(0); TLRPC.TL_auth_checkRecoveryPassword req = new TLRPC.TL_auth_checkRecoveryPassword(); req.code = code; String finalCode = code; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { needHideProgress(false); nextPressed = false; if (response instanceof TLRPC.TL_boolTrue) { Bundle params = new Bundle(); params.putString("emailCode", finalCode); params.putString("password", passwordString); setPage(VIEW_NEW_PASSWORD_STAGE_1, true, params, false); } else { if (error == null || error.text.startsWith("CODE_INVALID")) { onPasscodeError(true); } else if (error.text.startsWith("FLOOD_WAIT")) { int time = Utilities.parseInt(error.text); String timeString; if (time < 60) { timeString = LocaleController.formatPluralString("Seconds", time); } else { timeString = LocaleController.formatPluralString("Minutes", time / 60); } needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); } else { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), error.text); } } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } @Override public boolean onBackPressed(boolean force) { needHideProgress(true); currentParams = null; nextPressed = false; return true; } @Override public void onShow() { super.onShow(); AndroidUtilities.runOnUIThread(() -> { inboxImageView.getAnimatedDrawable().setCurrentFrame(0, false); inboxImageView.playAnimation(); if (codeFieldContainer != null) { codeFieldContainer.codeField[0].requestFocus(); } }, SHOW_DELAY); } @Override public void saveStateParams(Bundle bundle) { String code = codeFieldContainer.getCode(); if (code != null && code.length() != 0) { bundle.putString("recoveryview_code", code); } if (currentParams != null) { bundle.putBundle("recoveryview_params", currentParams); } } @Override public void restoreStateParams(Bundle bundle) { currentParams = bundle.getBundle("recoveryview_params"); if (currentParams != null) { setParams(currentParams, true); } String code = bundle.getString("recoveryview_code"); if (code != null) { codeFieldContainer.setText(code); } } } public class LoginActivityNewPasswordView extends SlideView { private OutlineTextContainerView[] outlineFields; private EditTextBoldCursor[] codeField; private TextView titleTextView; private TextView confirmTextView; private TextView cancelButton; private ImageView passwordButton; private String emailCode; private String newPassword; private String passwordString; private TLRPC.TL_account_password currentPassword; private Bundle currentParams; private boolean nextPressed; private int currentStage; private boolean isPasswordVisible; public LoginActivityNewPasswordView(Context context, int stage) { super(context); currentStage = stage; setOrientation(VERTICAL); codeField = new EditTextBoldCursor[stage == 1 ? 1 : 2]; outlineFields = new OutlineTextContainerView[codeField.length]; titleTextView = new TextView(context); titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); titleTextView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); titleTextView.setText(LocaleController.getString(R.string.SetNewPassword)); addView(titleTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 8, AndroidUtilities.isSmallScreen() ? 16 : 72, 8, 0)); confirmTextView = new TextView(context); confirmTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); confirmTextView.setGravity(Gravity.CENTER_HORIZONTAL); confirmTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); addView(confirmTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 8, 6, 8, 16)); for (int a = 0; a < codeField.length; a++) { OutlineTextContainerView outlineField = new OutlineTextContainerView(context); outlineFields[a] = outlineField; outlineField.setText(LocaleController.getString(stage == 0 ? a == 0 ? R.string.PleaseEnterNewFirstPasswordHint : R.string.PleaseEnterNewSecondPasswordHint : R.string.PasswordHintPlaceholder)); codeField[a] = new EditTextBoldCursor(context); codeField[a].setCursorSize(AndroidUtilities.dp(20)); codeField[a].setCursorWidth(1.5f); codeField[a].setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI); codeField[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); codeField[a].setMaxLines(1); codeField[a].setBackground(null); int padding = AndroidUtilities.dp(16); codeField[a].setPadding(padding, padding, padding, padding); if (stage == 0) { codeField[a].setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); } codeField[a].setTransformationMethod(PasswordTransformationMethod.getInstance()); codeField[a].setTypeface(Typeface.DEFAULT); codeField[a].setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); EditText field = codeField[a]; boolean showPasswordButton = a == 0 && stage == 0; field.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { if (showPasswordButton) { if (passwordButton.getVisibility() != VISIBLE && !TextUtils.isEmpty(s)) { if (isPasswordVisible) { passwordButton.callOnClick(); } AndroidUtilities.updateViewVisibilityAnimated(passwordButton, true, 0.1f, true); } else if (passwordButton.getVisibility() != GONE && TextUtils.isEmpty(s)) { AndroidUtilities.updateViewVisibilityAnimated(passwordButton, false, 0.1f, true); } } } }); codeField[a].setOnFocusChangeListener((v, hasFocus) -> outlineField.animateSelection(hasFocus ? 1f : 0f)); if (showPasswordButton) { LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(HORIZONTAL); linearLayout.setGravity(Gravity.CENTER_VERTICAL); linearLayout.addView(codeField[a], LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f)); passwordButton = new ImageView(context); passwordButton.setImageResource(R.drawable.msg_message); AndroidUtilities.updateViewVisibilityAnimated(passwordButton, true, 0.1f, false); passwordButton.setOnClickListener(v -> { isPasswordVisible = !isPasswordVisible; for (int i = 0; i < codeField.length; i++) { int selectionStart = codeField[i].getSelectionStart(), selectionEnd = codeField[i].getSelectionEnd(); codeField[i].setInputType(InputType.TYPE_CLASS_TEXT | (isPasswordVisible ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD : InputType.TYPE_TEXT_VARIATION_PASSWORD)); codeField[i].setSelection(selectionStart, selectionEnd); } passwordButton.setTag(isPasswordVisible); passwordButton.setColorFilter(Theme.getColor(isPasswordVisible ? Theme.key_windowBackgroundWhiteInputFieldActivated : Theme.key_windowBackgroundWhiteHintText)); }); linearLayout.addView(passwordButton, LayoutHelper.createLinearRelatively(24, 24, 0, 0, 0, 14, 0)); outlineField.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); } else { outlineField.addView(codeField[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); } outlineField.attachEditText(codeField[a]); addView(outlineField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 16, 16, 16, 0)); int num = a; codeField[a].setOnEditorActionListener((textView, i, keyEvent) -> { if (num == 0 && codeField.length == 2) { codeField[1].requestFocus(); return true; } else if (i == EditorInfo.IME_ACTION_NEXT) { onNextPressed(null); return true; } return false; }); } if (stage == 0) { confirmTextView.setText(LocaleController.getString("PleaseEnterNewFirstPasswordLogin", R.string.PleaseEnterNewFirstPasswordLogin)); } else { confirmTextView.setText(LocaleController.getString("PasswordHintTextLogin", R.string.PasswordHintTextLogin)); } cancelButton = new TextView(context); cancelButton.setGravity(Gravity.CENTER | Gravity.LEFT); cancelButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); cancelButton.setLineSpacing(AndroidUtilities.dp(2), 1.0f); cancelButton.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); cancelButton.setText(LocaleController.getString(R.string.YourEmailSkip)); FrameLayout bottomContainer = new FrameLayout(context); bottomContainer.addView(cancelButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, (Build.VERSION.SDK_INT >= 21 ? 56 : 60), Gravity.BOTTOM, 0, 0, 0, 32)); addView(bottomContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); VerticalPositionAutoAnimator.attach(cancelButton); cancelButton.setOnClickListener(view -> { if (currentStage == 0) { recoverPassword(null, null); } else { recoverPassword(newPassword, null); } }); } @Override public void updateColors() { titleTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); confirmTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); for (EditTextBoldCursor editText : codeField) { editText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); editText.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated)); } for (OutlineTextContainerView outlineField : outlineFields) { outlineField.updateColor(); } cancelButton.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4)); if (passwordButton != null) { passwordButton.setColorFilter(Theme.getColor(isPasswordVisible ? Theme.key_windowBackgroundWhiteInputFieldActivated : Theme.key_windowBackgroundWhiteHintText)); passwordButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), 1)); } } @Override public boolean needBackButton() { return true; } @Override public void onCancelPressed() { nextPressed = false; } @Override public String getHeaderName() { return LocaleController.getString("NewPassword", R.string.NewPassword); } @Override public void setParams(Bundle params, boolean restore) { if (params == null) { return; } for (int a = 0; a < codeField.length; a++) { codeField[a].setText(""); } currentParams = params; emailCode = currentParams.getString("emailCode"); passwordString = currentParams.getString("password"); if (passwordString != null) { SerializedData data = new SerializedData(Utilities.hexToBytes(passwordString)); currentPassword = TLRPC.TL_account_password.TLdeserialize(data, data.readInt32(false), false); TwoStepVerificationActivity.initPasswordNewAlgo(currentPassword); } newPassword = currentParams.getString("new_password"); showKeyboard(codeField[0]); codeField[0].requestFocus(); } private void onPasscodeError(boolean clear, int num) { if (getParentActivity() == null) { return; } try { codeField[num].performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } catch (Exception ignore) {} AndroidUtilities.shakeView(codeField[num], 2, 0); } @Override public void onNextPressed(String code) { if (nextPressed) { return; } code = codeField[0].getText().toString(); if (code.length() == 0) { onPasscodeError(false, 0); return; } if (currentStage == 0) { if (!code.equals(codeField[1].getText().toString())) { onPasscodeError(false, 1); return; } Bundle params = new Bundle(); params.putString("emailCode", emailCode); params.putString("new_password", code); params.putString("password", passwordString); setPage(VIEW_NEW_PASSWORD_STAGE_2, true, params, false); } else { nextPressed = true; needShowProgress(0); recoverPassword(newPassword, code); } } private void recoverPassword(String password, String hint) { TLRPC.TL_auth_recoverPassword req = new TLRPC.TL_auth_recoverPassword(); req.code = emailCode; if (!TextUtils.isEmpty(password)) { req.flags |= 1; req.new_settings = new TLRPC.TL_account_passwordInputSettings(); req.new_settings.flags |= 1; req.new_settings.hint = hint != null ? hint : ""; req.new_settings.new_algo = currentPassword.new_algo; } Utilities.globalQueue.postRunnable(() -> { byte[] newPasswordBytes; if (password != null) { newPasswordBytes = AndroidUtilities.getStringBytes(password); } else { newPasswordBytes = null; } RequestDelegate requestDelegate = (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (error != null && ("SRP_ID_INVALID".equals(error.text) || "NEW_SALT_INVALID".equals(error.text))) { TLRPC.TL_account_getPassword getPasswordReq = new TLRPC.TL_account_getPassword(); ConnectionsManager.getInstance(currentAccount).sendRequest(getPasswordReq, (response2, error2) -> AndroidUtilities.runOnUIThread(() -> { if (error2 == null) { currentPassword = (TLRPC.TL_account_password) response2; TwoStepVerificationActivity.initPasswordNewAlgo(currentPassword); recoverPassword(password, hint); } }), ConnectionsManager.RequestFlagWithoutLogin); return; } needHideProgress(false); if (response instanceof TLRPC.auth_Authorization) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setPositiveButton(LocaleController.getString(R.string.Continue), (dialogInterface, i) -> onAuthSuccess((TLRPC.TL_auth_authorization) response)); if (TextUtils.isEmpty(password)) { builder.setMessage(LocaleController.getString(R.string.YourPasswordReset)); } else { builder.setMessage(LocaleController.getString(R.string.YourPasswordChangedSuccessText)); } builder.setTitle(LocaleController.getString(R.string.TwoStepVerificationTitle)); Dialog dialog = showDialog(builder.create()); if (dialog != null) { dialog.setCanceledOnTouchOutside(false); dialog.setCancelable(false); } } else if (error != null) { nextPressed = false; if (error.text.startsWith("FLOOD_WAIT")) { int time = Utilities.parseInt(error.text); String timeString; if (time < 60) { timeString = LocaleController.formatPluralString("Seconds", time); } else { timeString = LocaleController.formatPluralString("Minutes", time / 60); } needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); } else { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), error.text); } } }); if (currentPassword.new_algo instanceof TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) { if (password != null) { TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow algo = (TLRPC.TL_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow) currentPassword.new_algo; req.new_settings.new_password_hash = SRPHelper.getVBytes(newPasswordBytes, algo); if (req.new_settings.new_password_hash == null) { TLRPC.TL_error error = new TLRPC.TL_error(); error.text = "ALGO_INVALID"; requestDelegate.run(null, error); } } ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } else { TLRPC.TL_error error = new TLRPC.TL_error(); error.text = "PASSWORD_HASH_INVALID"; requestDelegate.run(null, error); } }); } @Override public boolean onBackPressed(boolean force) { needHideProgress(true); currentParams = null; nextPressed = false; return true; } @Override public void onShow() { super.onShow(); AndroidUtilities.runOnUIThread(() -> { if (codeField != null) { codeField[0].requestFocus(); codeField[0].setSelection(codeField[0].length()); AndroidUtilities.showKeyboard(codeField[0]); } }, SHOW_DELAY); } @Override public void saveStateParams(Bundle bundle) { if (currentParams != null) { bundle.putBundle("recoveryview_params" + currentStage, currentParams); } } @Override public void restoreStateParams(Bundle bundle) { currentParams = bundle.getBundle("recoveryview_params" + currentStage); if (currentParams != null) { setParams(currentParams, true); } } } public class LoginActivityRegisterView extends SlideView implements ImageUpdater.ImageUpdaterDelegate { private OutlineTextContainerView firstNameOutlineView, lastNameOutlineView; private EditTextBoldCursor firstNameField; private EditTextBoldCursor lastNameField; private BackupImageView avatarImage; private AvatarDrawable avatarDrawable; private View avatarOverlay; private RLottieImageView avatarEditor; private RadialProgressView avatarProgressView; private AnimatorSet avatarAnimation; private TextView descriptionTextView; private TextView wrongNumber; private TextView privacyView; private TextView titleTextView; private FrameLayout editTextContainer; private String requestPhone; private String phoneHash; private Bundle currentParams; private boolean nextPressed = false; private RLottieDrawable cameraDrawable; private RLottieDrawable cameraWaitDrawable; private boolean isCameraWaitAnimationAllowed = true; private ImageUpdater imageUpdater; private TLRPC.FileLocation avatar; private TLRPC.FileLocation avatarBig; private boolean createAfterUpload; public class LinkSpan extends ClickableSpan { @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setUnderlineText(false); } @Override public void onClick(View widget) { showTermsOfService(false); } } private void showTermsOfService(boolean needAccept) { if (currentTermsOfService == null) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("TermsOfService", R.string.TermsOfService)); if (needAccept) { builder.setPositiveButton(LocaleController.getString("Accept", R.string.Accept), (dialog, which) -> { currentTermsOfService.popup = false; onNextPressed(null); }); builder.setNegativeButton(LocaleController.getString("Decline", R.string.Decline), (dialog, which) -> { AlertDialog.Builder builder1 = new AlertDialog.Builder(getParentActivity()); builder1.setTitle(LocaleController.getString("TermsOfService", R.string.TermsOfService)); builder1.setMessage(LocaleController.getString("TosDecline", R.string.TosDecline)); builder1.setPositiveButton(LocaleController.getString("SignUp", R.string.SignUp), (dialog1, which1) -> { currentTermsOfService.popup = false; onNextPressed(null); }); builder1.setNegativeButton(LocaleController.getString("Decline", R.string.Decline), (dialog12, which12) -> { onBackPressed(true); setPage(VIEW_PHONE_INPUT, true, null, true); }); showDialog(builder1.create()); }); } else { builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); } SpannableStringBuilder text = new SpannableStringBuilder(currentTermsOfService.text); MessageObject.addEntitiesToText(text, currentTermsOfService.entities, false, false, false, false); builder.setMessage(text); showDialog(builder.create()); } public LoginActivityRegisterView(Context context) { super(context); setOrientation(VERTICAL); imageUpdater = new ImageUpdater(false); imageUpdater.setOpenWithFrontfaceCamera(true); imageUpdater.setSearchAvailable(false); imageUpdater.setUploadAfterSelect(false); imageUpdater.parentFragment = LoginActivity.this; imageUpdater.setDelegate(this); FrameLayout avatarContainer = new FrameLayout(context); addView(avatarContainer, LayoutHelper.createLinear(78, 78, Gravity.CENTER_HORIZONTAL)); avatarDrawable = new AvatarDrawable(); avatarImage = new BackupImageView(context) { @Override public void invalidate() { if (avatarOverlay != null) { avatarOverlay.invalidate(); } super.invalidate(); } @Override public void invalidate(int l, int t, int r, int b) { if (avatarOverlay != null) { avatarOverlay.invalidate(); } super.invalidate(l, t, r, b); } }; avatarImage.setRoundRadius(AndroidUtilities.dp(64)); avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_REGISTER); avatarDrawable.setInfo(5, null, null); avatarImage.setImageDrawable(avatarDrawable); avatarContainer.addView(avatarImage, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(0x55000000); avatarOverlay = new View(context) { @Override protected void onDraw(Canvas canvas) { if (avatarImage != null && avatarProgressView.getVisibility() == VISIBLE) { paint.setAlpha((int) (0x55 * avatarImage.getImageReceiver().getCurrentAlpha() * avatarProgressView.getAlpha())); canvas.drawCircle(getMeasuredWidth() / 2.0f, getMeasuredHeight() / 2.0f, getMeasuredWidth() / 2.0f, paint); } } }; avatarContainer.addView(avatarOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); avatarOverlay.setOnClickListener(view -> { imageUpdater.openMenu(avatar != null, () -> { avatar = null; avatarBig = null; showAvatarProgress(false, true); avatarImage.setImage(null, null, avatarDrawable, null); avatarEditor.setImageResource(R.drawable.actions_setphoto); avatarEditor.setAnimation(cameraDrawable); cameraDrawable.setCurrentFrame(0); isCameraWaitAnimationAllowed = true; }, dialog -> { if (!imageUpdater.isUploadingImage()) { avatarEditor.setAnimation(cameraDrawable); cameraDrawable.setCustomEndFrame(86); avatarEditor.setOnAnimationEndListener(() -> isCameraWaitAnimationAllowed = true); avatarEditor.playAnimation(); } else { avatarEditor.setAnimation(cameraDrawable); cameraDrawable.setCurrentFrame(0, false); isCameraWaitAnimationAllowed = true; } }); isCameraWaitAnimationAllowed = false; avatarEditor.setAnimation(cameraDrawable); cameraDrawable.setCurrentFrame(0); cameraDrawable.setCustomEndFrame(43); avatarEditor.playAnimation(); }); cameraDrawable = new RLottieDrawable(R.raw.camera, String.valueOf(R.raw.camera), AndroidUtilities.dp(70), AndroidUtilities.dp(70), false, null); cameraWaitDrawable = new RLottieDrawable(R.raw.camera_wait, String.valueOf(R.raw.camera_wait), AndroidUtilities.dp(70), AndroidUtilities.dp(70), false, null); avatarEditor = new RLottieImageView(context) { @Override public void invalidate(int l, int t, int r, int b) { super.invalidate(l, t, r, b); avatarOverlay.invalidate(); } @Override public void invalidate() { super.invalidate(); avatarOverlay.invalidate(); } }; avatarEditor.setScaleType(ImageView.ScaleType.CENTER); avatarEditor.setAnimation(cameraDrawable); avatarEditor.setEnabled(false); avatarEditor.setClickable(false); avatarContainer.addView(avatarEditor, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); avatarEditor.addOnAttachStateChangeListener(new OnAttachStateChangeListener() { private long lastRun = System.currentTimeMillis(); private boolean isAttached; private Runnable cameraWaitCallback = () -> { if (isAttached) { if (isCameraWaitAnimationAllowed && System.currentTimeMillis() - lastRun >= 10000) { avatarEditor.setAnimation(cameraWaitDrawable); cameraWaitDrawable.setCurrentFrame(0, false); cameraWaitDrawable.setOnAnimationEndListener(() -> AndroidUtilities.runOnUIThread(()->{ cameraDrawable.setCurrentFrame(0, false); avatarEditor.setAnimation(cameraDrawable); })); avatarEditor.playAnimation(); lastRun = System.currentTimeMillis(); } avatarEditor.postDelayed(this.cameraWaitCallback, 1000); } }; @Override public void onViewAttachedToWindow(View v) { isAttached = true; v.post(cameraWaitCallback); } @Override public void onViewDetachedFromWindow(View v) { isAttached = false; v.removeCallbacks(cameraWaitCallback); } }); avatarProgressView = new RadialProgressView(context) { @Override public void setAlpha(float alpha) { super.setAlpha(alpha); avatarOverlay.invalidate(); } }; avatarProgressView.setSize(AndroidUtilities.dp(30)); avatarProgressView.setProgressColor(0xffffffff); avatarContainer.addView(avatarProgressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); showAvatarProgress(false, false); titleTextView = new TextView(context); titleTextView.setText(LocaleController.getString(R.string.RegistrationProfileInfo)); titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); titleTextView.setGravity(Gravity.CENTER_HORIZONTAL); addView(titleTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 8, 12, 8, 0)); descriptionTextView = new TextView(context); descriptionTextView.setText(LocaleController.getString("RegisterText2", R.string.RegisterText2)); descriptionTextView.setGravity(Gravity.CENTER_HORIZONTAL); descriptionTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); descriptionTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); addView(descriptionTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 8, 6, 8, 0)); editTextContainer = new FrameLayout(context); addView(editTextContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 8, 21, 8, 0)); firstNameOutlineView = new OutlineTextContainerView(context); firstNameOutlineView.setText(LocaleController.getString(R.string.FirstName)); firstNameField = new EditTextBoldCursor(context); firstNameField.setCursorSize(AndroidUtilities.dp(20)); firstNameField.setCursorWidth(1.5f); firstNameField.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI); firstNameField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); firstNameField.setMaxLines(1); firstNameField.setInputType(InputType.TYPE_TEXT_FLAG_CAP_WORDS); firstNameField.setOnFocusChangeListener((v, hasFocus) -> firstNameOutlineView.animateSelection(hasFocus ? 1f : 0f)); firstNameField.setBackground(null); firstNameField.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(16), AndroidUtilities.dp(16), AndroidUtilities.dp(16)); firstNameOutlineView.attachEditText(firstNameField); firstNameOutlineView.addView(firstNameField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); firstNameField.setOnEditorActionListener((textView, i, keyEvent) -> { if (i == EditorInfo.IME_ACTION_NEXT) { lastNameField.requestFocus(); return true; } return false; }); lastNameOutlineView = new OutlineTextContainerView(context); lastNameOutlineView.setText(LocaleController.getString(R.string.LastName)); lastNameField = new EditTextBoldCursor(context); lastNameField.setCursorSize(AndroidUtilities.dp(20)); lastNameField.setCursorWidth(1.5f); lastNameField.setImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI); lastNameField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); lastNameField.setMaxLines(1); lastNameField.setInputType(InputType.TYPE_TEXT_FLAG_CAP_WORDS); lastNameField.setOnFocusChangeListener((v, hasFocus) -> lastNameOutlineView.animateSelection(hasFocus ? 1f : 0f)); lastNameField.setBackground(null); lastNameField.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(16), AndroidUtilities.dp(16), AndroidUtilities.dp(16)); lastNameOutlineView.attachEditText(lastNameField); lastNameOutlineView.addView(lastNameField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); lastNameField.setOnEditorActionListener((textView, i, keyEvent) -> { if (i == EditorInfo.IME_ACTION_DONE || i == EditorInfo.IME_ACTION_NEXT) { onNextPressed(null); return true; } return false; }); buildEditTextLayout(AndroidUtilities.isSmallScreen()); wrongNumber = new TextView(context); wrongNumber.setText(LocaleController.getString("CancelRegistration", R.string.CancelRegistration)); wrongNumber.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_HORIZONTAL); wrongNumber.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); wrongNumber.setLineSpacing(AndroidUtilities.dp(2), 1.0f); wrongNumber.setPadding(0, AndroidUtilities.dp(24), 0, 0); wrongNumber.setVisibility(GONE); addView(wrongNumber, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 0, 20, 0, 0)); wrongNumber.setOnClickListener(view -> { if (radialProgressView.getTag() != null) { return; } onBackPressed(false); }); FrameLayout privacyLayout = new FrameLayout(context); addView(privacyLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.BOTTOM)); privacyView = new TextView(context); privacyView.setMovementMethod(new AndroidUtilities.LinkMovementMethodMy()); privacyView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, AndroidUtilities.isSmallScreen() ? 13 : 14); privacyView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); privacyView.setGravity(Gravity.CENTER_VERTICAL); privacyLayout.addView(privacyView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 56 : 60, Gravity.LEFT | Gravity.BOTTOM, 14, 0, 70, 32)); VerticalPositionAutoAnimator.attach(privacyView); String str = LocaleController.getString("TermsOfServiceLogin", R.string.TermsOfServiceLogin); SpannableStringBuilder text = new SpannableStringBuilder(str); int index1 = str.indexOf('*'); int index2 = str.lastIndexOf('*'); if (index1 != -1 && index2 != -1 && index1 != index2) { text.replace(index2, index2 + 1, ""); text.replace(index1, index1 + 1, ""); text.setSpan(new LinkSpan(), index1, index2 - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } privacyView.setText(text); } @Override public void updateColors() { avatarDrawable.invalidateSelf(); titleTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); descriptionTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); firstNameField.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); firstNameField.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated)); lastNameField.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); lastNameField.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated)); wrongNumber.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4)); privacyView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); privacyView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText)); firstNameOutlineView.updateColor(); lastNameOutlineView.updateColor(); } private void buildEditTextLayout(boolean small) { boolean firstHasFocus = firstNameField.hasFocus(), lastHasFocus = lastNameField.hasFocus(); editTextContainer.removeAllViews(); if (small) { LinearLayout linearLayout = new LinearLayout(getParentActivity()); linearLayout.setOrientation(HORIZONTAL); firstNameOutlineView.setText(LocaleController.getString(R.string.FirstNameSmall)); lastNameOutlineView.setText(LocaleController.getString(R.string.LastNameSmall)); linearLayout.addView(firstNameOutlineView, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, 0, 0, 8, 0)); linearLayout.addView(lastNameOutlineView, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f, 8, 0, 0, 0)); editTextContainer.addView(linearLayout); if (firstHasFocus) { firstNameField.requestFocus(); AndroidUtilities.showKeyboard(firstNameField); } else if (lastHasFocus) { lastNameField.requestFocus(); AndroidUtilities.showKeyboard(lastNameField); } } else { firstNameOutlineView.setText(LocaleController.getString(R.string.FirstName)); lastNameOutlineView.setText(LocaleController.getString(R.string.LastName)); editTextContainer.addView(firstNameOutlineView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP, 8, 0, 8, 0)); editTextContainer.addView(lastNameOutlineView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP, 8, 82, 8, 0)); } } @Override public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize) { AndroidUtilities.runOnUIThread(() -> { avatar = smallSize.location; avatarBig = bigSize.location; avatarImage.setImage(ImageLocation.getForLocal(avatar), "50_50", avatarDrawable, null); }); } private void showAvatarProgress(boolean show, boolean animated) { if (avatarEditor == null) { return; } if (avatarAnimation != null) { avatarAnimation.cancel(); avatarAnimation = null; } if (animated) { avatarAnimation = new AnimatorSet(); if (show) { avatarProgressView.setVisibility(View.VISIBLE); avatarAnimation.playTogether(ObjectAnimator.ofFloat(avatarEditor, View.ALPHA, 0.0f), ObjectAnimator.ofFloat(avatarProgressView, View.ALPHA, 1.0f)); } else { avatarEditor.setVisibility(View.VISIBLE); avatarAnimation.playTogether(ObjectAnimator.ofFloat(avatarEditor, View.ALPHA, 1.0f), ObjectAnimator.ofFloat(avatarProgressView, View.ALPHA, 0.0f)); } avatarAnimation.setDuration(180); avatarAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (avatarAnimation == null || avatarEditor == null) { return; } if (show) { avatarEditor.setVisibility(View.INVISIBLE); } else { avatarProgressView.setVisibility(View.INVISIBLE); } avatarAnimation = null; } @Override public void onAnimationCancel(Animator animation) { avatarAnimation = null; } }); avatarAnimation.start(); } else { if (show) { avatarEditor.setAlpha(1.0f); avatarEditor.setVisibility(View.INVISIBLE); avatarProgressView.setAlpha(1.0f); avatarProgressView.setVisibility(View.VISIBLE); } else { avatarEditor.setAlpha(1.0f); avatarEditor.setVisibility(View.VISIBLE); avatarProgressView.setAlpha(0.0f); avatarProgressView.setVisibility(View.INVISIBLE); } } } @Override public boolean onBackPressed(boolean force) { if (!force) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString(R.string.Warning)); builder.setMessage(LocaleController.getString("AreYouSureRegistration", R.string.AreYouSureRegistration)); builder.setNegativeButton(LocaleController.getString("Stop", R.string.Stop), (dialogInterface, i) -> { onBackPressed(true); setPage(VIEW_PHONE_INPUT, true, null, true); hidePrivacyView(); }); builder.setPositiveButton(LocaleController.getString("Continue", R.string.Continue), null); showDialog(builder.create()); return false; } needHideProgress(true); nextPressed = false; currentParams = null; return true; } @Override public String getHeaderName() { return LocaleController.getString("YourName", R.string.YourName); } @Override public void onCancelPressed() { nextPressed = false; } @Override public boolean needBackButton() { return true; } @Override public void onShow() { super.onShow(); if (privacyView != null) { if (restoringState) { privacyView.setAlpha(1f); } else { privacyView.setAlpha(0f); privacyView.animate().alpha(1f).setDuration(200).setStartDelay(300).setInterpolator(AndroidUtilities.decelerateInterpolator).start(); } } if (firstNameField != null) { firstNameField.requestFocus(); firstNameField.setSelection(firstNameField.length()); AndroidUtilities.showKeyboard(firstNameField); } AndroidUtilities.runOnUIThread(() -> { if (firstNameField != null) { firstNameField.requestFocus(); firstNameField.setSelection(firstNameField.length()); AndroidUtilities.showKeyboard(firstNameField); } }, SHOW_DELAY); } @Override public void setParams(Bundle params, boolean restore) { if (params == null) { return; } firstNameField.setText(""); lastNameField.setText(""); requestPhone = params.getString("phoneFormated"); phoneHash = params.getString("phoneHash"); currentParams = params; } @Override public void onNextPressed(String code) { if (nextPressed) { return; } if (currentTermsOfService != null && currentTermsOfService.popup) { showTermsOfService(true); return; } if (firstNameField.length() == 0) { onFieldError(firstNameOutlineView, true); return; } nextPressed = true; TLRPC.TL_auth_signUp req = new TLRPC.TL_auth_signUp(); req.phone_code_hash = phoneHash; req.phone_number = requestPhone; req.first_name = firstNameField.getText().toString(); req.last_name = lastNameField.getText().toString(); needShowProgress(0); ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { nextPressed = false; if (response instanceof TLRPC.TL_auth_authorization) { hidePrivacyView(); showDoneButton(false, true); postDelayed(() -> { needHideProgress(false, false); AndroidUtilities.hideKeyboard(fragmentView.findFocus()); onAuthSuccess((TLRPC.TL_auth_authorization) response, true); if (avatarBig != null) { TLRPC.FileLocation avatar = avatarBig; Utilities.cacheClearQueue.postRunnable(()-> MessagesController.getInstance(currentAccount).uploadAndApplyUserAvatar(avatar)); } }, 150); } else { needHideProgress(false); if (error.text.contains("PHONE_NUMBER_INVALID")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("InvalidCode", R.string.InvalidCode)); } else if (error.text.contains("PHONE_CODE_EXPIRED")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("CodeExpired", R.string.CodeExpired)); } else if (error.text.contains("FIRSTNAME_INVALID")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("InvalidFirstName", R.string.InvalidFirstName)); } else if (error.text.contains("LASTNAME_INVALID")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("InvalidLastName", R.string.InvalidLastName)); } else { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), error.text); } } }), ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); } @Override public void saveStateParams(Bundle bundle) { String first = firstNameField.getText().toString(); if (first.length() != 0) { bundle.putString("registerview_first", first); } String last = lastNameField.getText().toString(); if (last.length() != 0) { bundle.putString("registerview_last", last); } if (currentTermsOfService != null) { SerializedData data = new SerializedData(currentTermsOfService.getObjectSize()); currentTermsOfService.serializeToStream(data); String str = Base64.encodeToString(data.toByteArray(), Base64.DEFAULT); bundle.putString("terms", str); data.cleanup(); } if (currentParams != null) { bundle.putBundle("registerview_params", currentParams); } } @Override public void restoreStateParams(Bundle bundle) { currentParams = bundle.getBundle("registerview_params"); if (currentParams != null) { setParams(currentParams, true); } try { String terms = bundle.getString("terms"); if (terms != null) { byte[] arr = Base64.decode(terms, Base64.DEFAULT); if (arr != null) { SerializedData data = new SerializedData(arr); currentTermsOfService = TLRPC.TL_help_termsOfService.TLdeserialize(data, data.readInt32(false), false); data.cleanup(); } } } catch (Exception e) { FileLog.e(e); } String first = bundle.getString("registerview_first"); if (first != null) { firstNameField.setText(first); } String last = bundle.getString("registerview_last"); if (last != null) { lastNameField.setText(last); } } private void hidePrivacyView() { privacyView.animate().alpha(0f).setDuration(150).setStartDelay(0).setInterpolator(AndroidUtilities.accelerateInterpolator).start(); } } private boolean showKeyboard(View editText) { if (!isCustomKeyboardVisible()) { return AndroidUtilities.showKeyboard(editText); } return true; } public LoginActivity setIntroView(View intro, TextView startButton) { introView = intro; startMessagingButton = startButton; isAnimatingIntro = true; return this; } @Override protected AnimatorSet onCustomTransitionAnimation(boolean isOpen, Runnable callback) { if (isOpen && introView != null) { TransformableLoginButtonView transformButton = new TransformableLoginButtonView(fragmentView.getContext()); transformButton.setButtonText(startMessagingButton.getPaint(), startMessagingButton.getText().toString()); int oldTransformWidth = startMessagingButton.getWidth(), oldTransformHeight = startMessagingButton.getHeight(); int newTransformSize = floatingButtonIcon.getLayoutParams().width; ViewGroup.MarginLayoutParams transformParams = new FrameLayout.LayoutParams(oldTransformWidth, oldTransformHeight); transformButton.setLayoutParams(transformParams); int[] loc = new int[2]; fragmentView.getLocationInWindow(loc); int fragmentX = loc[0], fragmentY = loc[1]; startMessagingButton.getLocationInWindow(loc); float fromX = loc[0] - fragmentX, fromY = loc[1] - fragmentY; transformButton.setTranslationX(fromX); transformButton.setTranslationY(fromY); int toX = getParentLayout().getWidth() - floatingButtonIcon.getLayoutParams().width - ((ViewGroup.MarginLayoutParams)floatingButtonContainer.getLayoutParams()).rightMargin - getParentLayout().getPaddingLeft() - getParentLayout().getPaddingRight(), toY = getParentLayout().getHeight() - floatingButtonIcon.getLayoutParams().height - ((ViewGroup.MarginLayoutParams)floatingButtonContainer.getLayoutParams()).bottomMargin - (isCustomKeyboardVisible() ? AndroidUtilities.dp(CustomPhoneKeyboardView.KEYBOARD_HEIGHT_DP) : 0) - getParentLayout().getPaddingTop() - getParentLayout().getPaddingBottom(); ValueAnimator animator = ValueAnimator.ofFloat(0, 1); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { floatingButtonContainer.setVisibility(View.INVISIBLE); keyboardLinearLayout.setAlpha(0); fragmentView.setBackgroundColor(Color.TRANSPARENT); startMessagingButton.setVisibility(View.INVISIBLE); FrameLayout frameLayout = (FrameLayout) fragmentView; frameLayout.addView(transformButton); } @Override public void onAnimationEnd(Animator animation) { keyboardLinearLayout.setAlpha(1); startMessagingButton.setVisibility(View.VISIBLE); fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); floatingButtonContainer.setVisibility(View.VISIBLE); FrameLayout frameLayout = (FrameLayout) fragmentView; frameLayout.removeView(transformButton); if (animationFinishCallback != null) { AndroidUtilities.runOnUIThread(animationFinishCallback); animationFinishCallback = null; } isAnimatingIntro = false; callback.run(); } }); int bgColor = Theme.getColor(Theme.key_windowBackgroundWhite); int initialAlpha = Color.alpha(bgColor); animator.addUpdateListener(animation -> { float val = (float) animation.getAnimatedValue(); keyboardLinearLayout.setAlpha(val); fragmentView.setBackgroundColor(ColorUtils.setAlphaComponent(bgColor, (int) (initialAlpha * val))); float inverted = 1f - val; slideViewsContainer.setTranslationY(AndroidUtilities.dp(20) * inverted); if (!isCustomKeyboardForceDisabled()) { keyboardView.setTranslationY(keyboardView.getLayoutParams().height * inverted); floatingButtonContainer.setTranslationY(keyboardView.getLayoutParams().height * inverted); } introView.setTranslationY(-AndroidUtilities.dp(20) * val); float sc = 0.95f + 0.05f * inverted; introView.setScaleX(sc); introView.setScaleY(sc); transformParams.width = (int) (oldTransformWidth + (newTransformSize - oldTransformWidth) * val); transformParams.height = (int) (oldTransformHeight + (newTransformSize - oldTransformHeight) * val); transformButton.requestLayout(); transformButton.setProgress(val); transformButton.setTranslationX(fromX + (toX - fromX) * val); transformButton.setTranslationY(fromY + (toY - fromY) * val); }); animator.setInterpolator(CubicBezierInterpolator.DEFAULT); AnimatorSet set = new AnimatorSet(); set.setDuration(300); set.playTogether(animator); set.start(); return set; } return null; } private void updateColors() { Context context = getParentActivity(); Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_chats_actionBackground), Theme.getColor(Theme.key_chats_actionPressedBackground)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); drawable = combinedDrawable; } floatingButtonContainer.setBackground(drawable); backButtonView.setColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); backButtonView.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector))); radialProgressView.setProgressColor(Theme.getColor(Theme.key_chats_actionBackground)); floatingButtonIcon.setColor(Theme.getColor(Theme.key_chats_actionIcon)); floatingButtonIcon.setBackgroundColor(Theme.getColor(Theme.key_chats_actionBackground)); floatingProgressView.setProgressColor(Theme.getColor(Theme.key_chats_actionIcon)); for (SlideView slideView : views) { slideView.updateColors(); } keyboardView.updateColors(); if (phoneNumberConfirmView != null) { phoneNumberConfirmView.updateColors(); } } @Override public ArrayList getThemeDescriptions() { return SimpleThemeDescription.createThemeDescriptions(this::updateColors, Theme.key_windowBackgroundWhiteBlackText, Theme.key_windowBackgroundWhiteGrayText6, Theme.key_windowBackgroundWhiteHintText, Theme.key_listSelector, Theme.key_chats_actionBackground, Theme.key_chats_actionIcon, Theme.key_windowBackgroundWhiteInputField, Theme.key_windowBackgroundWhiteInputFieldActivated, Theme.key_windowBackgroundWhiteValueText, Theme.key_dialogTextRed, Theme.key_windowBackgroundWhiteGrayText, Theme.key_checkbox, Theme.key_windowBackgroundWhiteBlueText4, Theme.key_changephoneinfo_image2, Theme.key_chats_actionPressedBackground, Theme.key_windowBackgroundWhiteRedText2, Theme.key_windowBackgroundWhiteLinkText, Theme.key_checkboxSquareUnchecked, Theme.key_checkboxSquareBackground, Theme.key_checkboxSquareCheck, Theme.key_dialogBackground, Theme.key_dialogTextGray2, Theme.key_dialogTextBlack); } private void tryResetAccount(String requestPhone, String phoneHash, String phoneCode) { if (radialProgressView.getTag() != null) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setMessage(LocaleController.getString("ResetMyAccountWarningText", R.string.ResetMyAccountWarningText)); builder.setTitle(LocaleController.getString("ResetMyAccountWarning", R.string.ResetMyAccountWarning)); builder.setPositiveButton(LocaleController.getString("ResetMyAccountWarningReset", R.string.ResetMyAccountWarningReset), (dialogInterface, i) -> { needShowProgress(0); TLRPC.TL_account_deleteAccount req = new TLRPC.TL_account_deleteAccount(); req.reason = "Forgot password"; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { needHideProgress(false); if (error == null) { if (requestPhone == null || phoneHash == null || phoneCode == null) { setPage(VIEW_PHONE_INPUT, true, null, true); return; } Bundle params = new Bundle(); params.putString("phoneFormated", requestPhone); params.putString("phoneHash", phoneHash); params.putString("code", phoneCode); setPage(VIEW_REGISTER, true, params, false); } else { if (error.text.equals("2FA_RECENT_CONFIRM")) { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), LocaleController.getString("ResetAccountCancelledAlert", R.string.ResetAccountCancelledAlert)); } else if (error.text.startsWith("2FA_CONFIRM_WAIT_")) { Bundle params = new Bundle(); params.putString("phoneFormated", requestPhone); params.putString("phoneHash", phoneHash); params.putString("code", phoneCode); params.putInt("startTime", ConnectionsManager.getInstance(currentAccount).getCurrentTime()); params.putInt("waitTime", Utilities.parseInt(error.text.replace("2FA_CONFIRM_WAIT_", ""))); setPage(VIEW_RESET_WAIT, true, params, false); } else { needShowAlert(LocaleController.getString(R.string.RestorePasswordNoEmailTitle), error.text); } } }), ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagFailOnServerErrors); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } private final static class PhoneNumberConfirmView extends FrameLayout { private IConfirmDialogCallback callback; private ViewGroup fragmentView; private View fabContainer; private View blurredView; private View dimmView; private TransformableLoginButtonView fabTransform; private RadialProgressView floatingProgressView; private FrameLayout popupFabContainer; private TextView confirmMessageView; private TextView numberView; private TextView editTextView; private TextView confirmTextView; private FrameLayout popupLayout; private boolean dismissed; private PhoneNumberConfirmView(@NonNull Context context, ViewGroup fragmentView, View fabContainer, String numberText, IConfirmDialogCallback callback) { super(context); this.fragmentView = fragmentView; this.fabContainer = fabContainer; this.callback = callback; blurredView = new View(getContext()); blurredView.setOnClickListener(v -> dismiss()); addView(blurredView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); dimmView = new View(getContext()); dimmView.setBackgroundColor(0x40000000); dimmView.setAlpha(0); addView(dimmView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); fabTransform = new TransformableLoginButtonView(getContext()); fabTransform.setTransformType(TransformableLoginButtonView.TRANSFORM_ARROW_CHECK); fabTransform.setDrawBackground(false); popupFabContainer = new FrameLayout(context); popupFabContainer.addView(fabTransform, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); popupFabContainer.setOnClickListener(v -> callback.onFabPressed(this, fabTransform)); floatingProgressView = new RadialProgressView(context); floatingProgressView.setSize(AndroidUtilities.dp(22)); floatingProgressView.setAlpha(0.0f); floatingProgressView.setScaleX(0.1f); floatingProgressView.setScaleY(0.1f); popupFabContainer.addView(floatingProgressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); popupFabContainer.setContentDescription(LocaleController.getString(R.string.Done)); addView(popupFabContainer, LayoutHelper.createFrame(Build.VERSION.SDK_INT >= 21 ? 56 : 60, Build.VERSION.SDK_INT >= 21 ? 56 : 60)); popupLayout = new FrameLayout(context); addView(popupLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 140, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 24, 0, 24, 0)); confirmMessageView = new TextView(context); confirmMessageView.setText(LocaleController.getString(R.string.ConfirmCorrectNumber)); confirmMessageView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); confirmMessageView.setSingleLine(); popupLayout.addView(confirmMessageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 24, 20, 24, 0)); numberView = new TextView(context); numberView.setText(numberText); numberView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); numberView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); numberView.setSingleLine(); popupLayout.addView(numberView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 24, 48, 24, 0)); int buttonPadding = AndroidUtilities.dp(16); int buttonMargin = 8; editTextView = new TextView(context); editTextView.setText(LocaleController.getString(R.string.Edit)); editTextView.setSingleLine(); editTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); editTextView.setBackground(Theme.getRoundRectSelectorDrawable(AndroidUtilities.dp(6), Theme.getColor(Theme.key_changephoneinfo_image2))); editTextView.setOnClickListener(v -> callback.onEditPressed(this, editTextView)); editTextView.setTypeface(Typeface.DEFAULT_BOLD); editTextView.setPadding(buttonPadding, buttonPadding / 2, buttonPadding, buttonPadding / 2); popupLayout.addView(editTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), buttonMargin, buttonMargin, buttonMargin, buttonMargin)); confirmTextView = new TextView(context); confirmTextView.setText(LocaleController.getString(R.string.CheckPhoneNumberYes)); confirmTextView.setSingleLine(); confirmTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); confirmTextView.setBackground(Theme.getRoundRectSelectorDrawable(AndroidUtilities.dp(6), Theme.getColor(Theme.key_changephoneinfo_image2))); confirmTextView.setOnClickListener(v -> callback.onConfirmPressed(this, confirmTextView)); confirmTextView.setTypeface(Typeface.DEFAULT_BOLD); confirmTextView.setPadding(buttonPadding, buttonPadding / 2, buttonPadding, buttonPadding / 2); popupLayout.addView(confirmTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT), buttonMargin, buttonMargin, buttonMargin, buttonMargin)); updateFabPosition(); updateColors(); } private void updateFabPosition() { int[] loc = new int[2]; fragmentView.getLocationInWindow(loc); int fragmentX = loc[0], fragmentY = loc[1]; fabContainer.getLocationInWindow(loc); popupFabContainer.setTranslationX(loc[0] - fragmentX); popupFabContainer.setTranslationY(loc[1] - fragmentY); requestLayout(); } private void updateColors() { fabTransform.setColor(Theme.getColor(Theme.key_chats_actionIcon)); fabTransform.setBackgroundColor(Theme.getColor(Theme.key_chats_actionBackground)); popupLayout.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(12), Theme.getColor(Theme.key_dialogBackground))); confirmMessageView.setTextColor(Theme.getColor(Theme.key_dialogTextGray2)); numberView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); editTextView.setTextColor(Theme.getColor(Theme.key_changephoneinfo_image2)); confirmTextView.setTextColor(Theme.getColor(Theme.key_changephoneinfo_image2)); popupFabContainer.setBackground(Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_chats_actionBackground), Theme.getColor(Theme.key_chats_actionPressedBackground))); floatingProgressView.setProgressColor(Theme.getColor(Theme.key_chats_actionIcon)); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); int height = popupLayout.getMeasuredHeight(); int popupBottom = (int) (popupFabContainer.getTranslationY() - AndroidUtilities.dp(32)); popupLayout.layout(popupLayout.getLeft(), popupBottom - height, popupLayout.getRight(), popupBottom); } private void show() { ValueAnimator anim = ValueAnimator.ofFloat(0, 1).setDuration(250); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { fabContainer.setVisibility(GONE); // TODO: Generify this code, currently it's a clone float scaleFactor = 10; int w = (int) (fragmentView.getMeasuredWidth() / scaleFactor); int h = (int) (fragmentView.getMeasuredHeight() / scaleFactor); Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.scale(1.0f / scaleFactor, 1.0f / scaleFactor); fragmentView.draw(canvas); Utilities.stackBlurBitmap(bitmap, Math.max(8, Math.max(w, h) / 150)); blurredView.setBackground(new BitmapDrawable(getContext().getResources(), bitmap)); blurredView.setAlpha(0.0f); blurredView.setVisibility(View.VISIBLE); fragmentView.addView(PhoneNumberConfirmView.this); } @Override public void onAnimationEnd(Animator animation) { if (AndroidUtilities.isAccessibilityTouchExplorationEnabled()) { popupFabContainer.requestFocus(); } } }); anim.addUpdateListener(animation -> { float val = (float) animation.getAnimatedValue(); fabTransform.setProgress(val); blurredView.setAlpha(val); dimmView.setAlpha(val); popupLayout.setAlpha(val); float scale = 0.5f + val * 0.5f; popupLayout.setScaleX(scale); popupLayout.setScaleY(scale); }); anim.setInterpolator(CubicBezierInterpolator.DEFAULT); anim.start(); } private void animateProgress(Runnable callback) { ValueAnimator animator = ValueAnimator.ofFloat(0, 1); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { callback.run(); } }); animator.addUpdateListener(animation -> { float val = (float) animation.getAnimatedValue(); float scale = 0.1f + 0.9f * (1f - val); fabTransform.setScaleX(scale); fabTransform.setScaleY(scale); fabTransform.setAlpha(1f - val); scale = 0.1f + 0.9f * val; floatingProgressView.setScaleX(scale); floatingProgressView.setScaleY(scale); floatingProgressView.setAlpha(val); }); animator.setDuration(150); animator.start(); } private void dismiss() { if (dismissed) return; dismissed = true; callback.onDismiss(this); ValueAnimator anim = ValueAnimator.ofFloat(1, 0).setDuration(250); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (getParent() instanceof ViewGroup) { ((ViewGroup) getParent()).removeView(PhoneNumberConfirmView.this); } fabContainer.setVisibility(VISIBLE); } }); anim.addUpdateListener(animation -> { float val = (float) animation.getAnimatedValue(); blurredView.setAlpha(val); dimmView.setAlpha(val); fabTransform.setProgress(val); popupLayout.setAlpha(val); float scale = 0.5f + val * 0.5f; popupLayout.setScaleX(scale); popupLayout.setScaleY(scale); }); anim.setInterpolator(CubicBezierInterpolator.DEFAULT); anim.start(); } private interface IConfirmDialogCallback { void onFabPressed(PhoneNumberConfirmView confirmView, TransformableLoginButtonView fab); void onEditPressed(PhoneNumberConfirmView confirmView, TextView editTextView); void onConfirmPressed(PhoneNumberConfirmView confirmView, TextView confirmTextView); void onDismiss(PhoneNumberConfirmView confirmView); } } private interface PhoneNumberExclusionRule { int modifyHintLengthRequirement(int lengthFrom); } @Override public boolean isLightStatusBar() { int color = Theme.getColor(Theme.key_windowBackgroundWhite, null, true); return ColorUtils.calculateLuminance(color) > 0.7f; } // NekoX Changes @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.updateLoginToken) { regenerateLoginToken(false); } } @Override public boolean onFragmentCreate() { SharedConfig.loginingAccount = currentAccount; ApplicationLoader.loadAccount(currentAccount); return true; } private void fillNextCodeParamsSilent(Bundle params, TLRPC.TL_auth_sentCode res) { params.putString("phoneHash", res.phone_code_hash); if (res.next_type instanceof TLRPC.TL_auth_codeTypeCall) { params.putInt("nextType", 4); } else if (res.next_type instanceof TLRPC.TL_auth_codeTypeFlashCall) { params.putInt("nextType", 3); } else if (res.next_type instanceof TLRPC.TL_auth_codeTypeSms) { params.putInt("nextType", 2); } if (res.type instanceof TLRPC.TL_auth_sentCodeTypeApp) { params.putInt("type", 1); params.putInt("length", res.type.length); } else { if (res.timeout == 0) { res.timeout = 60; } params.putInt("timeout", res.timeout * 1000); if (res.type instanceof TLRPC.TL_auth_sentCodeTypeCall) { params.putInt("type", 4); params.putInt("length", res.type.length); } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeFlashCall) { params.putInt("type", 3); params.putString("pattern", res.type.pattern); } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeSms) { params.putInt("type", 2); params.putInt("length", res.type.length); } } } private void doBotLogin(Context context) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(LocaleController.getString("BotLogin", R.string.BotLogin)); final EditTextBoldCursor editText = new EditTextBoldCursor(context) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(64), MeasureSpec.EXACTLY)); } }; editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); editText.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); editText.setHintText(LocaleController.getString("BotToken", R.string.BotToken)); editText.setHeaderHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader)); editText.setSingleLine(true); editText.setFocusable(true); editText.setTransformHintToHeader(true); editText.setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), Theme.getColor(Theme.key_windowBackgroundWhiteRedText3)); editText.setImeOptions(EditorInfo.IME_ACTION_DONE); editText.setBackgroundDrawable(null); editText.requestFocus(); editText.setPadding(0, 0, 0, 0); ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) editText.getLayoutParams(); if (layoutParams != null) { if (layoutParams instanceof FrameLayout.LayoutParams) { ((FrameLayout.LayoutParams) layoutParams).gravity = Gravity.CENTER_HORIZONTAL; } layoutParams.rightMargin = layoutParams.leftMargin = AndroidUtilities.dp(24); layoutParams.height = AndroidUtilities.dp(36); editText.setLayoutParams(layoutParams); } builder.setView(editText); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { if (getParentActivity() == null) { return; } String token = editText.getText().toString(); if (token.length() == 0) { needShowAlert(LocaleController.getString("NekoX", R.string.NekoX), LocaleController.getString("InvalidAccessToken", R.string.InvalidAccessToken)); return; } ConnectionsManager.getInstance(currentAccount).cleanup(false); final TLRPC.TL_auth_importBotAuthorization req = new TLRPC.TL_auth_importBotAuthorization(); req.api_hash = NekoXConfig.currentAppHash(); req.api_id = NekoXConfig.currentAppId(); req.bot_auth_token = token; req.flags = 0; int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (error == null) { TLRPC.TL_auth_authorization res = (TLRPC.TL_auth_authorization) response; ConnectionsManager.getInstance(currentAccount).setUserId(res.user.id); UserConfig.getInstance(currentAccount).clearConfig(); MessagesController.getInstance(currentAccount).cleanup(); UserConfig.getInstance(currentAccount).syncContacts = syncContacts; UserConfig.getInstance(currentAccount).setCurrentUser(res.user); UserConfig.getInstance(currentAccount).saveConfig(true); MessagesStorage.getInstance(currentAccount).cleanup(true); ArrayList users = new ArrayList<>(); users.add(res.user); MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, true, true); MessagesController.getInstance(currentAccount).putUser(res.user, false); ConnectionsManager.getInstance(currentAccount).updateDcSettings(); needFinishActivity(false, res.setup_password_required, res.otherwise_relogin_days); } else { if (error.code == 401) { ConnectionsManager.native_cleanUp(currentAccount, true); } if (error.text != null) { if (error.text.contains("ACCESS_TOKEN_INVALID")) { needShowAlert(LocaleController.getString("NekoX", R.string.NekoX), LocaleController.getString("InvalidAccessToken", R.string.InvalidAccessToken)); } else if (error.text.startsWith("FLOOD_WAIT")) { needShowAlert(LocaleController.getString("NekoX", R.string.NekoX), LocaleController.getString("FloodWait", R.string.FloodWait)); } else if (error.code != -1000) { needShowAlert(LocaleController.getString("NekoX", R.string.NekoX), error.code + ": " + error.text); } } } needHideProgress(false); }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagTryDifferentDc | ConnectionsManager.RequestFlagEnableUnauthorized); needShowProgress(reqId); }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); builder.show().setOnShowListener(dialog -> { editText.requestFocus(); AndroidUtilities.showKeyboard(editText); }); } private void regenerateLoginToken(Boolean refresh) { getNotificationCenter().removeObserver(this, NotificationCenter.updateLoginToken); if (getParentActivity() == null || isFinished) return; if (exportLoginTokenDialog != null && exportLoginTokenDialog.isShowing()) { exportLoginTokenDialog.dismiss(); } else if (refresh) return; exportLoginTokenProgress = new AlertDialog(getParentActivity(), 3); exportLoginTokenProgress.setCanCancel(false); exportLoginTokenProgress.show(); if (exportLoginTokenRequest == null) { exportLoginTokenRequest = new TLRPC.TL_auth_exportLoginToken(); exportLoginTokenRequest.api_id = NekoXConfig.currentAppId(); exportLoginTokenRequest.api_hash = NekoXConfig.currentAppHash(); exportLoginTokenRequest.except_ids = new ArrayList<>(); for (int a : SharedConfig.activeAccounts) { UserConfig userConfig = UserConfig.getInstance(a); if (!userConfig.isClientActivated()) { continue; } exportLoginTokenRequest.except_ids.add(userConfig.clientUserId); } } getNotificationCenter().addObserver(this, NotificationCenter.updateLoginToken); getConnectionsManager().sendRequest(exportLoginTokenRequest, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (getParentActivity() == null) return; try { exportLoginTokenProgress.dismiss(); } catch (Exception ignore) { } if (response instanceof TLRPC.TL_auth_loginToken) { exportLoginTokenDialog = ProxyUtil.showQrDialog(getParentActivity(), "tg://login?token=" + cn.hutool.core.codec.Base64.encodeUrlSafe(((TLRPC.TL_auth_loginToken) response).token)); int delay = (int) (((TLRPC.TL_auth_loginToken) response).expires - System.currentTimeMillis() / 1000); if (delay < 0 || delay > 20) delay = 20; if (BuildVars.DEBUG_VERSION) { AlertUtil.showToast("Refresh after " + delay + "s"); } AndroidUtilities.runOnUIThread(() -> regenerateLoginToken(true), delay * 1000L); } else if (response instanceof TLRPC.TL_auth_loginTokenMigrateTo) { checkMigrateTo((TLRPC.TL_auth_loginTokenMigrateTo) response); } else if (response instanceof TLRPC.TL_auth_loginTokenSuccess) { processLoginByTokenFinish((TLRPC.TL_auth_loginTokenSuccess) response); } else { processError(error); } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagTryDifferentDc | ConnectionsManager.RequestFlagEnableUnauthorized); } private void checkMigrateTo(TLRPC.TL_auth_loginTokenMigrateTo response) { getNotificationCenter().removeObserver(this, NotificationCenter.updateLoginToken); ConnectionsManager.native_moveToDatacenter(currentAccount, response.dc_id); exportLoginTokenProgress.show(); TLRPC.TL_auth_importLoginToken request = new TLRPC.TL_auth_importLoginToken(); request.token = response.token; getConnectionsManager().sendRequest(request, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { exportLoginTokenProgress.dismiss(); if (error1 != null) { processError(error1); } else if (response1 instanceof TLRPC.TL_auth_loginTokenSuccess) { processLoginByTokenFinish((TLRPC.TL_auth_loginTokenSuccess) response1); } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagTryDifferentDc | ConnectionsManager.RequestFlagEnableUnauthorized); } private void processError(TLRPC.TL_error error) { if (error.text.contains("SESSION_PASSWORD_NEEDED")) { exportLoginTokenProgress.show(); TLRPC.TL_account_getPassword req2 = new TLRPC.TL_account_getPassword(); ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response1, error1) -> AndroidUtilities.runOnUIThread(() -> { exportLoginTokenProgress.dismiss(); showDoneButton(false, true); if (error1 == null) { TLRPC.TL_account_password password = (TLRPC.TL_account_password) response1; if (!TwoStepVerificationActivity.canHandleCurrentPassword(password, true)) { AlertsCreator.showUpdateAppAlert(getParentActivity(), LocaleController.getString("UpdateAppAlert", R.string.UpdateAppAlert), true); return; } Bundle bundle = new Bundle(); SerializedData data = new SerializedData(password.getObjectSize()); password.serializeToStream(data); bundle.putString("password", Utilities.bytesToHex(data.toByteArray())); setPage(LoginActivity.VIEW_PASSWORD, true, bundle, false); } else { needShowAlert(LocaleController.getString("NekoX", R.string.NekoX), error1.text); } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); } else { AlertUtil.showToast(error); exportLoginTokenRequest = null; if (!error.text.contains("CONNECTION_NOT_INITED")) regenerateLoginToken(false); } } private void processLoginByTokenFinish(TLRPC.TL_auth_loginTokenSuccess authLoginTokenSuccess) { getNotificationCenter().removeObserver(this, NotificationCenter.updateLoginToken); TLRPC.auth_Authorization authorization = authLoginTokenSuccess.authorization; if (authorization instanceof TLRPC.TL_auth_authorizationSignUpRequired) { TLRPC.TL_auth_authorizationSignUpRequired authorizationI = (TLRPC.TL_auth_authorizationSignUpRequired) authorization; if (authorizationI.terms_of_service != null) { currentTermsOfService = authorizationI.terms_of_service; } setPage(VIEW_REGISTER, true, new Bundle(), false); } else { onAuthSuccess((TLRPC.TL_auth_authorization) authorization); } } }