kopia lustrzana https://github.com/ryukoposting/Signal-Android
255 wiersze
11 KiB
Java
255 wiersze
11 KiB
Java
package org.thoughtcrime.securesms.registration.fragments;
|
|
|
|
import android.Manifest;
|
|
import android.annotation.SuppressLint;
|
|
import android.content.Context;
|
|
import android.os.Build;
|
|
import android.os.Bundle;
|
|
import android.text.TextUtils;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.widget.Button;
|
|
import android.widget.TextView;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.annotation.RequiresApi;
|
|
import androidx.annotation.StringRes;
|
|
import androidx.fragment.app.FragmentActivity;
|
|
import androidx.lifecycle.ViewModelProvider;
|
|
import androidx.navigation.ActivityNavigator;
|
|
import androidx.navigation.Navigation;
|
|
import androidx.navigation.fragment.NavHostFragment;
|
|
|
|
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
|
import com.google.i18n.phonenumbers.Phonenumber;
|
|
|
|
import org.greenrobot.eventbus.EventBus;
|
|
import org.signal.core.util.logging.Log;
|
|
import org.signal.devicetransfer.DeviceToDeviceTransferService;
|
|
import org.signal.devicetransfer.TransferStatus;
|
|
import org.thoughtcrime.securesms.LoggingFragment;
|
|
import org.thoughtcrime.securesms.R;
|
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
|
import org.thoughtcrime.securesms.permissions.Permissions;
|
|
import org.thoughtcrime.securesms.registration.viewmodel.RegistrationViewModel;
|
|
import org.thoughtcrime.securesms.util.BackupUtil;
|
|
import org.thoughtcrime.securesms.util.CommunicationActions;
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
import org.thoughtcrime.securesms.util.Util;
|
|
import org.thoughtcrime.securesms.util.navigation.SafeNavigation;
|
|
import org.thoughtcrime.securesms.util.views.CircularProgressMaterialButton;
|
|
|
|
import java.util.Optional;
|
|
|
|
import static org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView;
|
|
|
|
public final class WelcomeFragment extends LoggingFragment {
|
|
|
|
private static final String TAG = Log.tag(WelcomeFragment.class);
|
|
|
|
private static final String[] PERMISSIONS = { Manifest.permission.WRITE_CONTACTS,
|
|
Manifest.permission.READ_CONTACTS,
|
|
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
|
Manifest.permission.READ_EXTERNAL_STORAGE,
|
|
Manifest.permission.READ_PHONE_STATE };
|
|
@RequiresApi(26)
|
|
private static final String[] PERMISSIONS_API_26 = { Manifest.permission.WRITE_CONTACTS,
|
|
Manifest.permission.READ_CONTACTS,
|
|
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
|
Manifest.permission.READ_EXTERNAL_STORAGE,
|
|
Manifest.permission.READ_PHONE_STATE,
|
|
Manifest.permission.READ_PHONE_NUMBERS };
|
|
@RequiresApi(26)
|
|
private static final String[] PERMISSIONS_API_29 = { Manifest.permission.WRITE_CONTACTS,
|
|
Manifest.permission.READ_CONTACTS,
|
|
Manifest.permission.READ_PHONE_STATE,
|
|
Manifest.permission.READ_PHONE_NUMBERS };
|
|
|
|
private static final @StringRes int RATIONALE = R.string.RegistrationActivity_signal_needs_access_to_your_contacts_and_media_in_order_to_connect_with_friends;
|
|
private static final @StringRes int RATIONALE_API_29 = R.string.RegistrationActivity_signal_needs_access_to_your_contacts_in_order_to_connect_with_friends;
|
|
private static final int[] HEADERS = { R.drawable.ic_contacts_white_48dp, R.drawable.ic_folder_white_48dp };
|
|
private static final int[] HEADERS_API_29 = { R.drawable.ic_contacts_white_48dp };
|
|
|
|
private CircularProgressMaterialButton continueButton;
|
|
private RegistrationViewModel viewModel;
|
|
|
|
@Override
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
return inflater.inflate(R.layout.fragment_registration_welcome, container, false);
|
|
}
|
|
|
|
@Override
|
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
|
super.onViewCreated(view, savedInstanceState);
|
|
|
|
viewModel = new ViewModelProvider(requireActivity()).get(RegistrationViewModel.class);
|
|
|
|
if (viewModel.isReregister()) {
|
|
if (viewModel.hasRestoreFlowBeenShown()) {
|
|
Log.i(TAG, "We've come back to the home fragment on a restore, user must be backing out");
|
|
if (!Navigation.findNavController(view).popBackStack()) {
|
|
FragmentActivity activity = requireActivity();
|
|
activity.finish();
|
|
ActivityNavigator.applyPopAnimationsToPendingTransition(activity);
|
|
}
|
|
return;
|
|
}
|
|
|
|
initializeNumber();
|
|
|
|
Log.i(TAG, "Skipping restore because this is a reregistration.");
|
|
viewModel.setWelcomeSkippedOnRestore();
|
|
SafeNavigation.safeNavigate(NavHostFragment.findNavController(this),
|
|
WelcomeFragmentDirections.actionSkipRestore());
|
|
} else {
|
|
|
|
setDebugLogSubmitMultiTapView(view.findViewById(R.id.image));
|
|
setDebugLogSubmitMultiTapView(view.findViewById(R.id.title));
|
|
|
|
continueButton = view.findViewById(R.id.welcome_continue_button);
|
|
continueButton.setOnClickListener(this::continueClicked);
|
|
|
|
Button restoreFromBackup = view.findViewById(R.id.welcome_transfer_or_restore);
|
|
restoreFromBackup.setOnClickListener(this::restoreFromBackupClicked);
|
|
|
|
TextView welcomeTermsButton = view.findViewById(R.id.welcome_terms_button);
|
|
welcomeTermsButton.setOnClickListener(v -> onTermsClicked());
|
|
|
|
if (!canUserSelectBackup()) {
|
|
restoreFromBackup.setText(R.string.registration_activity__transfer_account);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
super.onResume();
|
|
if (EventBus.getDefault().getStickyEvent(TransferStatus.class) != null) {
|
|
Log.i(TAG, "Found existing transferStatus, redirect to transfer flow");
|
|
SafeNavigation.safeNavigate(NavHostFragment.findNavController(this), R.id.action_welcomeFragment_to_deviceTransferSetup);
|
|
} else {
|
|
DeviceToDeviceTransferService.stop(requireContext());
|
|
}
|
|
}
|
|
|
|
private void continueClicked(@NonNull View view) {
|
|
boolean isUserSelectionRequired = BackupUtil.isUserSelectionRequired(requireContext());
|
|
|
|
Permissions.with(this)
|
|
.request(getContinuePermissions(isUserSelectionRequired))
|
|
.ifNecessary()
|
|
.withRationaleDialog(getString(getContinueRationale(isUserSelectionRequired)), getContinueHeaders(isUserSelectionRequired))
|
|
.onAnyResult(() -> gatherInformationAndContinue(continueButton))
|
|
.execute();
|
|
}
|
|
|
|
private void restoreFromBackupClicked(@NonNull View view) {
|
|
boolean isUserSelectionRequired = BackupUtil.isUserSelectionRequired(requireContext());
|
|
|
|
Permissions.with(this)
|
|
.request(getContinuePermissions(isUserSelectionRequired))
|
|
.ifNecessary()
|
|
.withRationaleDialog(getString(getContinueRationale(isUserSelectionRequired)), getContinueHeaders(isUserSelectionRequired))
|
|
.onAnyResult(() -> gatherInformationAndChooseBackup(continueButton))
|
|
.execute();
|
|
}
|
|
|
|
private void gatherInformationAndContinue(@NonNull View view) {
|
|
continueButton.setSpinning();
|
|
|
|
RestoreBackupFragment.searchForBackup(backup -> {
|
|
Context context = getContext();
|
|
if (context == null) {
|
|
Log.i(TAG, "No context on fragment, must have navigated away.");
|
|
return;
|
|
}
|
|
|
|
TextSecurePreferences.setHasSeenWelcomeScreen(requireContext(), true);
|
|
|
|
initializeNumber();
|
|
|
|
continueButton.cancelSpinning();
|
|
|
|
if (backup == null) {
|
|
Log.i(TAG, "Skipping backup. No backup found, or no permission to look.");
|
|
SafeNavigation.safeNavigate(NavHostFragment.findNavController(this),
|
|
WelcomeFragmentDirections.actionSkipRestore());
|
|
} else {
|
|
SafeNavigation.safeNavigate(NavHostFragment.findNavController(this),
|
|
WelcomeFragmentDirections.actionRestore());
|
|
}
|
|
});
|
|
}
|
|
|
|
private void gatherInformationAndChooseBackup(@NonNull View view) {
|
|
TextSecurePreferences.setHasSeenWelcomeScreen(requireContext(), true);
|
|
|
|
initializeNumber();
|
|
|
|
SafeNavigation.safeNavigate(NavHostFragment.findNavController(this),
|
|
WelcomeFragmentDirections.actionTransferOrRestore());
|
|
}
|
|
|
|
@SuppressLint("MissingPermission")
|
|
private void initializeNumber() {
|
|
Optional<Phonenumber.PhoneNumber> localNumber = Optional.empty();
|
|
|
|
if (Permissions.hasAll(requireContext(), Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_PHONE_NUMBERS)) {
|
|
localNumber = Util.getDeviceNumber(requireContext());
|
|
} else {
|
|
Log.i(TAG, "No phone permission");
|
|
}
|
|
|
|
if (localNumber.isPresent()) {
|
|
Log.i(TAG, "Phone number detected");
|
|
Phonenumber.PhoneNumber phoneNumber = localNumber.get();
|
|
String nationalNumber = PhoneNumberUtil.getInstance().format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
|
|
|
|
viewModel.onNumberDetected(phoneNumber.getCountryCode(), nationalNumber);
|
|
} else {
|
|
Log.i(TAG, "No number detected");
|
|
Optional<String> simCountryIso = Util.getSimCountryIso(requireContext());
|
|
|
|
if (simCountryIso.isPresent() && !TextUtils.isEmpty(simCountryIso.get())) {
|
|
viewModel.onNumberDetected(PhoneNumberUtil.getInstance().getCountryCodeForRegion(simCountryIso.get()), "");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void onTermsClicked() {
|
|
CommunicationActions.openBrowserLink(requireContext(), RegistrationConstants.TERMS_AND_CONDITIONS_URL);
|
|
}
|
|
|
|
private boolean canUserSelectBackup() {
|
|
return BackupUtil.isUserSelectionRequired(requireContext()) &&
|
|
!viewModel.isReregister() &&
|
|
!SignalStore.settings().isBackupEnabled();
|
|
}
|
|
|
|
@SuppressLint("NewApi")
|
|
private static String[] getContinuePermissions(boolean isUserSelectionRequired) {
|
|
if (isUserSelectionRequired) {
|
|
return PERMISSIONS_API_29;
|
|
} else if (Build.VERSION.SDK_INT >= 26) {
|
|
return PERMISSIONS_API_26;
|
|
} else {
|
|
return PERMISSIONS;
|
|
}
|
|
}
|
|
|
|
private static @StringRes int getContinueRationale(boolean isUserSelectionRequired) {
|
|
return isUserSelectionRequired ? RATIONALE_API_29 : RATIONALE;
|
|
}
|
|
|
|
private static int[] getContinueHeaders(boolean isUserSelectionRequired) {
|
|
return isUserSelectionRequired ? HEADERS_API_29 : HEADERS;
|
|
}
|
|
}
|