Remove old device link flow.

This commit is contained in:
Greyson Parrelli 2024-10-17 08:18:28 -04:00
parent 6fcfd8fdb1
commit 898d5ccb78
14 changed files with 2 additions and 994 deletions

View file

@ -867,12 +867,6 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:exported="false"/>
<activity android:name=".DeviceActivity"
android:screenOrientation="portrait"
android:label="@string/AndroidManifest__linked_devices"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:exported="false"/>
<activity android:name=".logsubmit.SubmitDebugLogActivity"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"

View file

@ -1,266 +0,0 @@
package org.thoughtcrime.securesms;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Vibrator;
import android.text.TextUtils;
import android.transition.TransitionInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.ecc.Curve;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.qr.kitkat.ScanListener;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.jobs.LinkedDeviceInactiveCheckJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.signal.core.util.Base64;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
import org.whispersystems.signalservice.internal.push.DeviceLimitExceededException;
import java.io.IOException;
public class DeviceActivity extends PassphraseRequiredActivity
implements Button.OnClickListener, ScanListener, DeviceLinkFragment.LinkClickedListener
{
private static final String TAG = Log.tag(DeviceActivity.class);
private static final String EXTRA_DIRECT_TO_SCANNER = "add";
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
private DeviceAddFragment deviceAddFragment;
private DeviceListFragment deviceListFragment;
private DeviceLinkFragment deviceLinkFragment;
private MenuItem cameraSwitchItem = null;
public static Intent getIntentForScanner(Context context) {
Intent intent = new Intent(context, DeviceActivity.class);
intent.putExtra(EXTRA_DIRECT_TO_SCANNER, true);
return intent;
}
@Override
public void onPreCreate() {
dynamicTheme.onCreate(this);
dynamicLanguage.onCreate(this);
}
@Override
public void onCreate(Bundle bundle, boolean ready) {
setContentView(R.layout.device_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
requireSupportActionBar().setDisplayHomeAsUpEnabled(true);
requireSupportActionBar().setTitle(R.string.AndroidManifest__linked_devices);
this.deviceAddFragment = new DeviceAddFragment();
this.deviceListFragment = new DeviceListFragment();
this.deviceLinkFragment = new DeviceLinkFragment();
this.deviceListFragment.setAddDeviceButtonListener(this);
this.deviceAddFragment.setScanListener(this);
if (getIntent().getBooleanExtra(EXTRA_DIRECT_TO_SCANNER, false)) {
initFragment(R.id.fragment_container, deviceAddFragment, dynamicLanguage.getCurrentLocale());
} else {
initFragment(R.id.fragment_container, deviceListFragment, dynamicLanguage.getCurrentLocale());
}
}
@Override
public void onResume() {
super.onResume();
dynamicTheme.onResume(this);
dynamicLanguage.onResume(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.device_add, menu);
cameraSwitchItem = menu.findItem(R.id.device_add_camera_switch);
cameraSwitchItem.setVisible(false);
return super.onCreateOptionsMenu(menu);
}
public MenuItem getCameraSwitchItem() {
return cameraSwitchItem;
}
@Override
public void onClick(View v) {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.CameraXFragment_to_scan_qr_code_allow_camera), R.drawable.symbol_camera_24)
.withPermanentDenialDialog(getString(R.string.DeviceActivity_signal_needs_the_camera_permission_in_order_to_scan_a_qr_code), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_scan_qr_codes, getSupportFragmentManager())
.onAllGranted(() -> {
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<Void, Void, Integer>(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);
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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<List<Device>>,
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<List<Device>> onCreateLoader(int id, Bundle args) {
empty.setVisibility(View.GONE);
progressContainer.setVisibility(View.VISIBLE);
return new DeviceListLoader(getActivity(), accountManager);
}
@Override
public void onLoadFinished(@NonNull Loader<List<Device>> loader, List<Device> 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<List<Device>> 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<Void, Void, Boolean>(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<Device> {
private final int resource;
private final Locale locale;
public DeviceListAdapter(Context context, int resource, List<Device> 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;
}
}
}

View file

@ -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();
}
}

View file

@ -1,6 +1,5 @@
package org.thoughtcrime.securesms;
import android.content.Intent;
import android.os.Bundle;
import android.view.Window;

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:viewBindingIgnore="true"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/dsl_settings_toolbar" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>

View file

@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:viewBindingIgnore="true"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/halfway_guideline"
android:layout_width="match_parent"
android:layout_height="1dp"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<org.signal.qr.QrScannerView
android:id="@+id/scanner"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/halfway_guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<org.thoughtcrime.securesms.components.ShapeScrim
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/halfway_guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?android:windowBackground"
android:gravity="center"
android:orientation="vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/halfway_guideline">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/devices"
android:layout_width="129dp"
android:layout_height="129dp"
android:layout_marginBottom="16dp"
android:scaleType="fitXY"
android:src="@drawable/symbol_devices_24"
android:tint="@color/core_grey_25"
android:transitionName="devices" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/device_add_fragment__scan_the_qr_code_displayed_on_the_device_to_link"
android:textColor="?android:textColorSecondary" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,93 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:viewBindingIgnore="true"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/devices"
android:layout_width="129dp"
android:layout_height="129dp"
android:layout_marginBottom="25dp"
android:contentDescription="@string/device_link_fragment__link_device"
android:scaleType="fitXY"
android:src="@drawable/symbol_devices_24"
android:tint="@color/core_grey_25"
android:transitionName="devices" />
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="25dp"
android:layout_marginEnd="25dp">
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/signal_background_dialog">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textStyle="bold"
android:text="@string/DeviceProvisioningActivity_link_this_device"
android:textSize="16sp"/>
<View android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#1E000000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/DeviceProvisioningActivity_content_intro"
android:textSize="14sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/DeviceProvisioningActivity_content_bullets"
android:textSize="14sp"/>
<View android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#1E000000"/>
<LinearLayout android:id="@+id/link_device"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:gravity="center_vertical"
android:clickable="true">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:src="@drawable/symbol_check_24"
android:tint="@color/blue_400"
android:clickable="false"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@color/blue_400"
android:text="@string/device_link_fragment__link_device"
android:clickable="false"/>
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:viewBindingIgnore="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<LinearLayout
android:id="@+id/progress_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</LinearLayout>
<TextView
android:id="@+id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center|center_vertical"
android:layout_weight="1"
android:gravity="center|center_vertical"
android:paddingStart="16dip"
android:paddingEnd="16dip"
android:text="@string/device_list_fragment__no_devices_linked"
android:textSize="20sp"
android:visibility="gone"
tools:visibility="visible" />
<ListView
android:id="@id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:divider="@null"
android:drawSelectorOnTop="false"
android:paddingStart="@dimen/dsl_settings_gutter"
android:paddingEnd="@dimen/dsl_settings_gutter"
tools:visibility="gone" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/add_device"
style="@style/Widget.Material3.FloatingActionButton.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:contentDescription="@string/device_list_fragment__link_new_device"
android:focusable="true"
app:srcCompat="@drawable/ic_plus_24" />
</LinearLayout>

View file

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.DeviceListItem xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:viewBindingIgnore="true"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp">
<TextView android:id="@+id/name"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/signal_text_primary"
android:singleLine="true"
android:ellipsize="marquee"
android:layout_marginTop="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView android:id="@+id/created"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/signal_text_secondary"
android:fontFamily="sans-serif-light" />
<TextView android:id="@+id/active"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/signal_text_secondary"
android:fontFamily="sans-serif-light"
android:layout_marginBottom="8dp" />
</org.thoughtcrime.securesms.DeviceListItem>

View file

@ -43,13 +43,6 @@
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_appSettingsFragment_to_deviceActivity"
app:destination="@id/deviceActivity"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_appSettingsFragment_to_linkDeviceFragment"
app:destination="@id/linkDeviceFragment"
@ -232,13 +225,7 @@
<!-- endregion -->
<!-- Linked Devices V1-->
<activity
android:id="@+id/deviceActivity"
android:name="org.thoughtcrime.securesms.DeviceActivity"
android:label="device_activity" />
<!-- Linked Devices V2 -->
<!-- Linked Devices -->
<fragment
android:id="@+id/linkDeviceFragment"
android:name="org.thoughtcrime.securesms.linkdevice.LinkDeviceFragment"

View file

@ -43,13 +43,6 @@
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_appSettingsFragment_to_deviceActivity"
app:destination="@id/deviceActivity"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_appSettingsFragment_to_linkDeviceFragment"
app:destination="@id/linkDeviceFragment"
@ -232,13 +225,7 @@
<!-- endregion -->
<!-- Linked Devices V1-->
<activity
android:id="@+id/deviceActivity"
android:name="org.thoughtcrime.securesms.DeviceActivity"
android:label="device_activity" />
<!-- Linked Devices V2 -->
<!-- Linked Devices -->
<fragment
android:id="@+id/linkDeviceFragment"
android:name="org.thoughtcrime.securesms.linkdevice.LinkDeviceFragment"