diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ba24593718..28b6d88219 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -867,12 +867,6 @@ android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" android:exported="false"/> - - { - getSupportFragmentManager().beginTransaction() - .replace(R.id.fragment_container, deviceAddFragment) - .addToBackStack(null) - .commitAllowingStateLoss(); - }) - .onAnyDenied(() -> Toast.makeText(this, R.string.CameraXFragment_signal_needs_camera_access_scan_qr_code, Toast.LENGTH_LONG).show()) - .execute(); - } - - @Override - public void onQrDataFound(@NonNull final String data) { - ThreadUtil.runOnMain(() -> { - ((Vibrator)getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50); - Uri uri = Uri.parse(data); - deviceLinkFragment.setLinkClickedListener(uri, DeviceActivity.this); - - deviceAddFragment.setSharedElementReturnTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(R.transition.fragment_shared)); - deviceAddFragment.setExitTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(android.R.transition.fade)); - - deviceLinkFragment.setSharedElementEnterTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(R.transition.fragment_shared)); - deviceLinkFragment.setEnterTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(android.R.transition.fade)); - - getSupportFragmentManager().beginTransaction() - .addToBackStack(null) - .addSharedElement(deviceAddFragment.getDevicesImage(), "devices") - .replace(R.id.fragment_container, deviceLinkFragment) - .commit(); - - }); - } - - @SuppressLint("MissingSuperCall") - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults); - } - - @SuppressLint("StaticFieldLeak") - @Override - public void onLink(final Uri uri) { - new ProgressDialogAsyncTask(this, - R.string.DeviceProvisioningActivity_content_progress_title, - R.string.DeviceProvisioningActivity_content_progress_content) - { - private static final int SUCCESS = 0; - private static final int NO_DEVICE = 1; - private static final int NETWORK_ERROR = 2; - private static final int KEY_ERROR = 3; - private static final int LIMIT_EXCEEDED = 4; - private static final int BAD_CODE = 5; - - @Override - protected Integer doInBackground(Void... params) { - boolean isMultiDevice = TextSecurePreferences.isMultiDevice(DeviceActivity.this); - - try { - Context context = DeviceActivity.this; - SignalServiceAccountManager accountManager = AppDependencies.getSignalServiceAccountManager(); - String verificationCode = accountManager.getNewDeviceVerificationCode(); - String ephemeralId = uri.getQueryParameter("uuid"); - String publicKeyEncoded = uri.getQueryParameter("pub_key"); - - if (TextUtils.isEmpty(ephemeralId) || TextUtils.isEmpty(publicKeyEncoded)) { - Log.w(TAG, "UUID or Key is empty!"); - return BAD_CODE; - } - - ECPublicKey publicKey = Curve.decodePoint(Base64.decode(publicKeyEncoded), 0); - IdentityKeyPair aciIdentityKeyPair = SignalStore.account().getAciIdentityKey(); - IdentityKeyPair pniIdentityKeyPair = SignalStore.account().getPniIdentityKey(); - ProfileKey profileKey = ProfileKeyUtil.getSelfProfileKey(); - - TextSecurePreferences.setMultiDevice(DeviceActivity.this, true); - accountManager.addDevice(ephemeralId, publicKey, aciIdentityKeyPair, pniIdentityKeyPair, profileKey, SignalStore.svr().getOrCreateMasterKey(), verificationCode); - - return SUCCESS; - } catch (NotFoundException e) { - Log.w(TAG, e); - TextSecurePreferences.setMultiDevice(DeviceActivity.this, isMultiDevice); - return NO_DEVICE; - } catch (DeviceLimitExceededException e) { - Log.w(TAG, e); - TextSecurePreferences.setMultiDevice(DeviceActivity.this, isMultiDevice); - return LIMIT_EXCEEDED; - } catch (IOException e) { - Log.w(TAG, e); - TextSecurePreferences.setMultiDevice(DeviceActivity.this, isMultiDevice); - return NETWORK_ERROR; - } catch (InvalidKeyException e) { - Log.w(TAG, e); - TextSecurePreferences.setMultiDevice(DeviceActivity.this, isMultiDevice); - return KEY_ERROR; - } - } - - @Override - protected void onPostExecute(Integer result) { - super.onPostExecute(result); - - LinkedDeviceInactiveCheckJob.enqueue(); - - Context context = DeviceActivity.this; - - switch (result) { - case SUCCESS: - Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_success, Toast.LENGTH_SHORT).show(); - finish(); - return; - case NO_DEVICE: - Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_no_device, Toast.LENGTH_LONG).show(); - break; - case NETWORK_ERROR: - Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_network_error, Toast.LENGTH_LONG).show(); - break; - case KEY_ERROR: - Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_key_error, Toast.LENGTH_LONG).show(); - break; - case LIMIT_EXCEEDED: - Toast.makeText(context, R.string.DeviceProvisioningActivity_sorry_you_have_too_many_devices_linked_already, Toast.LENGTH_LONG).show(); - break; - case BAD_CODE: - Toast.makeText(context, R.string.DeviceActivity_sorry_this_is_not_a_valid_device_link_qr_code, Toast.LENGTH_LONG).show(); - break; - } - - getSupportFragmentManager().popBackStackImmediate(); - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/DeviceAddFragment.java b/app/src/main/java/org/thoughtcrime/securesms/DeviceAddFragment.java deleted file mode 100644 index 26e8235d10..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/DeviceAddFragment.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.thoughtcrime.securesms; - -import android.animation.Animator; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewAnimationUtils; -import android.view.ViewGroup; -import android.view.animation.DecelerateInterpolator; -import android.widget.ImageView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.view.ViewCompat; - -import org.signal.qr.QrScannerView; -import org.signal.qr.kitkat.ScanListener; -import org.thoughtcrime.securesms.mediasend.camerax.CameraXModelBlocklist; -import org.signal.core.util.concurrent.LifecycleDisposable; -import org.thoughtcrime.securesms.util.ViewUtil; - -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; -import io.reactivex.rxjava3.disposables.Disposable; - -public class DeviceAddFragment extends LoggingFragment { - - private final LifecycleDisposable lifecycleDisposable = new LifecycleDisposable(); - - private ImageView devicesImage; - private ScanListener scanListener; - private QrScannerView scannerView; - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) { - ViewGroup container = ViewUtil.inflate(inflater, viewGroup, R.layout.device_add_fragment); - - this.scannerView = container.findViewById(R.id.scanner); - this.devicesImage = container.findViewById(R.id.devices); - ViewCompat.setTransitionName(devicesImage, "devices"); - - container.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) - { - v.removeOnLayoutChangeListener(this); - - Animator reveal = ViewAnimationUtils.createCircularReveal(v, right, bottom, 0, (int) Math.hypot(right, bottom)); - reveal.setInterpolator(new DecelerateInterpolator(2f)); - reveal.setDuration(800); - reveal.start(); - } - }); - - scannerView.start(getViewLifecycleOwner(), CameraXModelBlocklist.isBlocklisted()); - - lifecycleDisposable.bindTo(getViewLifecycleOwner()); - - Disposable qrDisposable = scannerView - .getQrData() - .distinctUntilChanged() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(qrData -> { - if (scanListener != null) { - scanListener.onQrDataFound(qrData); - } - }); - - lifecycleDisposable.add(qrDisposable); - - return container; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - MenuItem switchCamera = ((DeviceActivity) requireActivity()).getCameraSwitchItem(); - - if (switchCamera != null) { - switchCamera.setVisible(true); - switchCamera.setOnMenuItemClickListener(v -> { - scannerView.toggleCamera(); - return true; - }); - } - } - - public ImageView getDevicesImage() { - return devicesImage; - } - - public void setScanListener(ScanListener scanListener) { - this.scanListener = scanListener; - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/DeviceLinkFragment.java b/app/src/main/java/org/thoughtcrime/securesms/DeviceLinkFragment.java deleted file mode 100644 index ab4e4bec71..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/DeviceLinkFragment.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.thoughtcrime.securesms; - -import android.content.res.Configuration; -import android.net.Uri; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; - -import androidx.annotation.NonNull; -import androidx.core.view.ViewCompat; -import androidx.fragment.app.Fragment; - -public class DeviceLinkFragment extends Fragment implements View.OnClickListener { - - private LinearLayout container; - private LinkClickedListener linkClickedListener; - private Uri uri; - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) { - this.container = (LinearLayout) inflater.inflate(R.layout.device_link_fragment, container, false); - this.container.findViewById(R.id.link_device).setOnClickListener(this); - ViewCompat.setTransitionName(container.findViewById(R.id.devices), "devices"); - - if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - container.setOrientation(LinearLayout.HORIZONTAL); - } else { - container.setOrientation(LinearLayout.VERTICAL); - } - - return this.container; - } - - @Override - public void onConfigurationChanged(@NonNull Configuration newConfiguration) { - super.onConfigurationChanged(newConfiguration); - if (newConfiguration.orientation == Configuration.ORIENTATION_LANDSCAPE) { - container.setOrientation(LinearLayout.HORIZONTAL); - } else { - container.setOrientation(LinearLayout.VERTICAL); - } - } - - public void setLinkClickedListener(Uri uri, LinkClickedListener linkClickedListener) { - this.uri = uri; - this.linkClickedListener = linkClickedListener; - } - - @Override - public void onClick(View v) { - if (linkClickedListener != null) { - linkClickedListener.onLink(uri); - } - } - - public interface LinkClickedListener { - void onLink(Uri uri); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/DeviceListFragment.java b/app/src/main/java/org/thoughtcrime/securesms/DeviceListFragment.java deleted file mode 100644 index 1012af6271..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/DeviceListFragment.java +++ /dev/null @@ -1,205 +0,0 @@ -package org.thoughtcrime.securesms; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.Context; -import android.os.AsyncTask; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.ListView; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; -import androidx.fragment.app.ListFragment; -import androidx.loader.app.LoaderManager; -import androidx.loader.content.Loader; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.google.android.material.floatingactionbutton.FloatingActionButton; - -import org.signal.core.util.logging.Log; -import org.thoughtcrime.securesms.database.loaders.DeviceListLoader; -import org.thoughtcrime.securesms.dependencies.AppDependencies; -import org.thoughtcrime.securesms.devicelist.Device; -import org.thoughtcrime.securesms.jobs.LinkedDeviceInactiveCheckJob; -import org.thoughtcrime.securesms.keyvalue.SignalStore; -import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; -import org.whispersystems.signalservice.api.SignalServiceAccountManager; - -import java.io.IOException; -import java.util.List; -import java.util.Locale; - -public class DeviceListFragment extends ListFragment - implements LoaderManager.LoaderCallbacks>, - ListView.OnItemClickListener, Button.OnClickListener -{ - - private static final String TAG = Log.tag(DeviceListFragment.class); - - private SignalServiceAccountManager accountManager; - private Locale locale; - private View empty; - private View progressContainer; - private FloatingActionButton addDeviceButton; - private Button.OnClickListener addDeviceButtonListener; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - this.locale = (Locale) requireArguments().getSerializable(PassphraseRequiredActivity.LOCALE_EXTRA); - } - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - this.accountManager = AppDependencies.getSignalServiceAccountManager(); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - View view = inflater.inflate(R.layout.device_list_fragment, container, false); - - this.empty = view.findViewById(R.id.empty); - this.progressContainer = view.findViewById(R.id.progress_container); - this.addDeviceButton = view.findViewById(R.id.add_device); - this.addDeviceButton.setOnClickListener(this); - - return view; - } - - @Override - public void onActivityCreated(Bundle bundle) { - super.onActivityCreated(bundle); - getLoaderManager().initLoader(0, null, this); - getListView().setOnItemClickListener(this); - } - - public void setAddDeviceButtonListener(Button.OnClickListener listener) { - this.addDeviceButtonListener = listener; - } - - @Override - public @NonNull Loader> onCreateLoader(int id, Bundle args) { - empty.setVisibility(View.GONE); - progressContainer.setVisibility(View.VISIBLE); - - return new DeviceListLoader(getActivity(), accountManager); - } - - @Override - public void onLoadFinished(@NonNull Loader> loader, List data) { - progressContainer.setVisibility(View.GONE); - - if (data == null) { - handleLoaderFailed(); - return; - } - - setListAdapter(new DeviceListAdapter(getActivity(), R.layout.device_list_item_view, data, locale)); - - if (data.isEmpty()) { - empty.setVisibility(View.VISIBLE); - TextSecurePreferences.setMultiDevice(getActivity(), false); - SignalStore.misc().setHasLinkedDevices(false); - } else { - SignalStore.misc().setHasLinkedDevices(true); - empty.setVisibility(View.GONE); - } - } - - @Override - public void onLoaderReset(@NonNull Loader> loader) { - setListAdapter(null); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - final String deviceName = ((DeviceListItem)view).getDeviceName(); - final long deviceId = ((DeviceListItem)view).getDeviceId(); - - AlertDialog.Builder builder = new MaterialAlertDialogBuilder(requireActivity()); - builder.setTitle(getString(R.string.DeviceListActivity_unlink_s, deviceName)); - builder.setMessage(R.string.DeviceListActivity_by_unlinking_this_device_it_will_no_longer_be_able_to_send_or_receive); - builder.setNegativeButton(android.R.string.cancel, null); - builder.setPositiveButton(android.R.string.ok, (dialog, which) -> handleDisconnectDevice(deviceId)); - builder.show(); - } - - private void handleLoaderFailed() { - AlertDialog.Builder builder = new MaterialAlertDialogBuilder(requireActivity()); - builder.setMessage(R.string.DeviceListActivity_network_connection_failed); - builder.setPositiveButton(R.string.DeviceListActivity_try_again, - (dialog, which) -> getLoaderManager().restartLoader(0, null, DeviceListFragment.this)); - - builder.setNegativeButton(android.R.string.cancel, (dialog, which) -> requireActivity().onBackPressed()); - builder.setOnCancelListener(dialog -> requireActivity().onBackPressed()); - - builder.show(); - } - - @SuppressLint("StaticFieldLeak") - private void handleDisconnectDevice(final long deviceId) { - new ProgressDialogAsyncTask(getActivity(), - R.string.DeviceListActivity_unlinking_device_no_ellipsis, - R.string.DeviceListActivity_unlinking_device) - { - @Override - protected Boolean doInBackground(Void... params) { - try { - accountManager.removeDevice(deviceId); - return true; - } catch (IOException e) { - Log.w(TAG, e); - return false; - } - } - - @Override - protected void onPostExecute(Boolean result) { - super.onPostExecute(result); - if (result) { - getLoaderManager().restartLoader(0, null, DeviceListFragment.this); - LinkedDeviceInactiveCheckJob.enqueue(); - } else { - Toast.makeText(getActivity(), R.string.DeviceListActivity_network_failed, Toast.LENGTH_LONG).show(); - } - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - - @Override - public void onClick(View v) { - if (addDeviceButtonListener != null) addDeviceButtonListener.onClick(v); - } - - private static class DeviceListAdapter extends ArrayAdapter { - - private final int resource; - private final Locale locale; - - public DeviceListAdapter(Context context, int resource, List objects, Locale locale) { - super(context, resource, objects); - this.resource = resource; - this.locale = locale; - } - - @Override - public @NonNull View getView(int position, View convertView, @NonNull ViewGroup parent) { - if (convertView == null) { - convertView = ((Activity)getContext()).getLayoutInflater().inflate(resource, parent, false); - } - - ((DeviceListItem)convertView).set(getItem(position), locale); - - return convertView; - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/DeviceListItem.java b/app/src/main/java/org/thoughtcrime/securesms/DeviceListItem.java deleted file mode 100644 index 5284945734..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/DeviceListItem.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.thoughtcrime.securesms; - -import android.content.Context; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.widget.LinearLayout; -import android.widget.TextView; - -import org.thoughtcrime.securesms.devicelist.Device; -import org.thoughtcrime.securesms.util.DateUtils; - -import java.util.Locale; - -public class DeviceListItem extends LinearLayout { - - private long deviceId; - private TextView name; - private TextView created; - private TextView lastActive; - - public DeviceListItem(Context context) { - super(context); - } - - public DeviceListItem(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - public void onFinishInflate() { - super.onFinishInflate(); - this.name = (TextView) findViewById(R.id.name); - this.created = (TextView) findViewById(R.id.created); - this.lastActive = (TextView) findViewById(R.id.active); - } - - public void set(Device deviceInfo, Locale locale) { - if (TextUtils.isEmpty(deviceInfo.getName())) this.name.setText(R.string.DeviceListItem_unnamed_device); - else this.name.setText(deviceInfo.getName()); - - this.created.setText(getContext().getString(R.string.DeviceListItem_linked_s, - DateUtils.getDayPrecisionTimeSpanString(getContext(), - locale, - deviceInfo.getCreated()))); - - this.lastActive.setText(getContext().getString(R.string.DeviceListItem_last_active_s, - DateUtils.getDayPrecisionTimeSpanString(getContext(), - locale, - deviceInfo.getLastSeen()))); - - this.deviceId = deviceInfo.getId(); - } - - public long getDeviceId() { - return deviceId; - } - - public String getDeviceName() { - return name.getText().toString(); - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/DeviceProvisioningActivity.java b/app/src/main/java/org/thoughtcrime/securesms/DeviceProvisioningActivity.java index 5b3308d6f7..0fbb60b03b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/DeviceProvisioningActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/DeviceProvisioningActivity.java @@ -1,6 +1,5 @@ package org.thoughtcrime.securesms; -import android.content.Intent; import android.os.Bundle; import android.view.Window; diff --git a/app/src/main/res/layout/device_activity.xml b/app/src/main/res/layout/device_activity.xml deleted file mode 100644 index e7dd5ceeed..0000000000 --- a/app/src/main/res/layout/device_activity.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/device_add_fragment.xml b/app/src/main/res/layout/device_add_fragment.xml deleted file mode 100644 index cd1a129aaf..0000000000 --- a/app/src/main/res/layout/device_add_fragment.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/device_link_fragment.xml b/app/src/main/res/layout/device_link_fragment.xml deleted file mode 100644 index 23a3a42622..0000000000 --- a/app/src/main/res/layout/device_link_fragment.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/device_list_fragment.xml b/app/src/main/res/layout/device_list_fragment.xml deleted file mode 100644 index 82e77f04e8..0000000000 --- a/app/src/main/res/layout/device_list_fragment.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/device_list_item_view.xml b/app/src/main/res/layout/device_list_item_view.xml deleted file mode 100644 index 5022722c1c..0000000000 --- a/app/src/main/res/layout/device_list_item_view.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/app_settings.xml b/app/src/main/res/navigation/app_settings.xml index b92fb855ad..7e9cde8598 100644 --- a/app/src/main/res/navigation/app_settings.xml +++ b/app/src/main/res/navigation/app_settings.xml @@ -43,13 +43,6 @@ app:exitAnim="@anim/fragment_open_exit" app:popEnterAnim="@anim/fragment_close_enter" app:popExitAnim="@anim/fragment_close_exit" /> - - - - - + - - - - - +