Skip to content

Commit 1c5d3ed

Browse files
committed
Allow registering as a linked device
1 parent aa747c0 commit 1c5d3ed

58 files changed

Lines changed: 1618 additions & 82 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import org.thoughtcrime.securesms.jobs.ProfileUploadJob;
6969
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
7070
import org.thoughtcrime.securesms.jobs.RefreshSvrCredentialsJob;
71+
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
7172
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
7273
import org.thoughtcrime.securesms.jobs.RetrieveRemoteAnnouncementsJob;
7374
import org.thoughtcrime.securesms.jobs.StoryOnboardingDownloadJob;
@@ -565,9 +566,14 @@ private void initializeCircumvention() {
565566
}
566567

567568
private void ensureProfileUploaded() {
568-
if (SignalStore.account().isRegistered() && !SignalStore.registrationValues().hasUploadedProfile() && !Recipient.self().getProfileName().isEmpty()) {
569-
Log.w(TAG, "User has a profile, but has not uploaded one. Uploading now.");
570-
ApplicationDependencies.getJobManager().add(new ProfileUploadJob());
569+
if (SignalStore.account().isRegistered()) {
570+
if (SignalStore.registrationValues().needDownloadProfileOrAvatar()) {
571+
Log.w(TAG, "User has linked a device, but has not yet downloaded the profile. Downloading now.");
572+
ApplicationDependencies.getJobManager().add(new RefreshOwnProfileJob());
573+
} else if (!SignalStore.registrationValues().hasUploadedProfile() && !Recipient.self().getProfileName().isEmpty()) {
574+
Log.w(TAG, "User has a profile, but has not uploaded one. Uploading now.");
575+
ApplicationDependencies.getJobManager().add(new ProfileUploadJob());
576+
}
571577
}
572578
}
573579

app/src/main/java/org/thoughtcrime/securesms/DeviceListFragment.java

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import androidx.loader.app.LoaderManager;
2121
import androidx.loader.content.Loader;
2222

23+
import com.annimon.stream.Stream;
24+
2325
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
2426
import com.google.android.material.floatingactionbutton.FloatingActionButton;
2527

@@ -31,6 +33,7 @@
3133
import org.thoughtcrime.securesms.util.TextSecurePreferences;
3234
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
3335
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
36+
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
3437

3538
import java.io.IOException;
3639
import java.util.List;
@@ -45,7 +48,6 @@ public class DeviceListFragment extends ListFragment
4548

4649
private SignalServiceAccountManager accountManager;
4750
private Locale locale;
48-
private View empty;
4951
private View progressContainer;
5052
private FloatingActionButton addDeviceButton;
5153
private Button.OnClickListener addDeviceButtonListener;
@@ -66,10 +68,13 @@ public void onAttach(@NonNull Context context) {
6668
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
6769
View view = inflater.inflate(R.layout.device_list_fragment, container, false);
6870

69-
this.empty = view.findViewById(R.id.empty);
7071
this.progressContainer = view.findViewById(R.id.progress_container);
7172
this.addDeviceButton = view.findViewById(R.id.add_device);
72-
this.addDeviceButton.setOnClickListener(this);
73+
if (SignalStore.account().isPrimaryDevice()) {
74+
this.addDeviceButton.setOnClickListener(this);
75+
} else {
76+
this.addDeviceButton.setVisibility(View.GONE);
77+
}
7378

7479
return view;
7580
}
@@ -87,7 +92,6 @@ public void setAddDeviceButtonListener(Button.OnClickListener listener) {
8792

8893
@Override
8994
public @NonNull Loader<List<Device>> onCreateLoader(int id, Bundle args) {
90-
empty.setVisibility(View.GONE);
9195
progressContainer.setVisibility(View.VISIBLE);
9296

9397
return new DeviceListLoader(getActivity(), accountManager);
@@ -102,16 +106,11 @@ public void onLoadFinished(@NonNull Loader<List<Device>> loader, List<Device> da
102106
return;
103107
}
104108

105-
setListAdapter(new DeviceListAdapter(getActivity(), R.layout.device_list_item_view, data, locale));
109+
setListAdapter(new DeviceListAdapter(getActivity(), R.layout.device_list_item_view, data, locale, SignalStore.account().getDeviceId()));
106110

107-
if (data.isEmpty()) {
108-
empty.setVisibility(View.VISIBLE);
109-
TextSecurePreferences.setMultiDevice(getActivity(), false);
110-
SignalStore.misc().setHasLinkedDevices(false);
111-
} else {
112-
SignalStore.misc().setHasLinkedDevices(true);
113-
empty.setVisibility(View.GONE);
114-
}
111+
boolean hasLinkedDevices = Stream.of(data).noneMatch(d -> d.getId() != SignalServiceAddress.DEFAULT_DEVICE_ID);
112+
TextSecurePreferences.setMultiDevice(getActivity(), SignalStore.account().isLinkedDevice() || hasLinkedDevices);
113+
SignalStore.misc().setHasLinkedDevices(hasLinkedDevices);
115114
}
116115

117116
@Override
@@ -123,6 +122,10 @@ public void onLoaderReset(@NonNull Loader<List<Device>> loader) {
123122
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
124123
final String deviceName = ((DeviceListItem)view).getDeviceName();
125124
final long deviceId = ((DeviceListItem)view).getDeviceId();
125+
if (deviceId == SignalServiceAddress.DEFAULT_DEVICE_ID || deviceId == SignalStore.account().getDeviceId()) {
126+
// Sanity check
127+
return;
128+
}
126129

127130
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(requireActivity());
128131
builder.setTitle(getString(R.string.DeviceListActivity_unlink_s, deviceName));
@@ -182,11 +185,13 @@ private static class DeviceListAdapter extends ArrayAdapter<Device> {
182185

183186
private final int resource;
184187
private final Locale locale;
188+
private final long thisDeviceId;
185189

186-
public DeviceListAdapter(Context context, int resource, List<Device> objects, Locale locale) {
190+
public DeviceListAdapter(Context context, int resource, List<Device> objects, Locale locale, long thisDeviceId) {
187191
super(context, resource, objects);
188192
this.resource = resource;
189193
this.locale = locale;
194+
this.thisDeviceId = thisDeviceId;
190195
}
191196

192197
@Override
@@ -195,9 +200,15 @@ public DeviceListAdapter(Context context, int resource, List<Device> objects, Lo
195200
convertView = ((Activity)getContext()).getLayoutInflater().inflate(resource, parent, false);
196201
}
197202

198-
((DeviceListItem)convertView).set(getItem(position), locale);
203+
((DeviceListItem)convertView).set(getItem(position), locale, thisDeviceId);
199204

200205
return convertView;
201206
}
207+
208+
@Override
209+
public boolean isEnabled(int position) {
210+
long deviceId = getItem(position).getId();
211+
return deviceId != SignalServiceAddress.DEFAULT_DEVICE_ID && deviceId != thisDeviceId;
212+
}
202213
}
203214
}

app/src/main/java/org/thoughtcrime/securesms/DeviceListItem.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,20 @@
55
import android.util.AttributeSet;
66
import android.widget.LinearLayout;
77
import android.widget.TextView;
8+
import android.view.View;
89

910
import org.thoughtcrime.securesms.devicelist.Device;
1011
import org.thoughtcrime.securesms.util.DateUtils;
12+
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
1113

1214
import java.util.Locale;
1315

1416
public class DeviceListItem extends LinearLayout {
1517

1618
private long deviceId;
1719
private TextView name;
20+
private View primary;
21+
private View thisDevice;
1822
private TextView created;
1923
private TextView lastActive;
2024

@@ -30,15 +34,19 @@ public DeviceListItem(Context context, AttributeSet attrs) {
3034
public void onFinishInflate() {
3135
super.onFinishInflate();
3236
this.name = (TextView) findViewById(R.id.name);
37+
this.primary = findViewById(R.id.primary);
38+
this.thisDevice = findViewById(R.id.this_device);
3339
this.created = (TextView) findViewById(R.id.created);
3440
this.lastActive = (TextView) findViewById(R.id.active);
3541
}
3642

37-
public void set(Device deviceInfo, Locale locale) {
38-
if (TextUtils.isEmpty(deviceInfo.getName())) this.name.setText(R.string.DeviceListItem_unnamed_device);
43+
public void set(Device deviceInfo, Locale locale, long thisDeviceId) {
44+
if (TextUtils.isEmpty(deviceInfo.getName())) this.name.setText(getContext().getString(R.string.DeviceListItem_device_d, deviceInfo.getId()));
3945
else this.name.setText(deviceInfo.getName());
4046

41-
this.created.setText(getContext().getString(R.string.DeviceListItem_linked_s,
47+
this.deviceId = deviceInfo.getId();
48+
49+
this.created.setText(getContext().getString(this.deviceId == SignalServiceAddress.DEFAULT_DEVICE_ID ? R.string.DeviceListItem_registered_s : R.string.DeviceListItem_linked_s,
4250
DateUtils.getDayPrecisionTimeSpanString(getContext(),
4351
locale,
4452
deviceInfo.getCreated())));
@@ -48,7 +56,8 @@ public void set(Device deviceInfo, Locale locale) {
4856
locale,
4957
deviceInfo.getLastSeen())));
5058

51-
this.deviceId = deviceInfo.getId();
59+
this.primary.setVisibility(this.deviceId == SignalServiceAddress.DEFAULT_DEVICE_ID ? View.VISIBLE : View.GONE);
60+
this.thisDevice.setVisibility(this.deviceId == thisDeviceId ? View.VISIBLE : View.GONE);
5261
}
5362

5463
public long getDeviceId() {

app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class AccountSettingsViewModel : ViewModel() {
1818

1919
private fun getCurrentState(): AccountSettingsState {
2020
return AccountSettingsState(
21-
hasPin = SignalStore.svr().hasPin() && !SignalStore.svr().hasOptedOut(),
21+
hasPin = (SignalStore.svr().hasPin() && !SignalStore.svr().hasOptedOut()) || SignalStore.storageService().hasStorageKeyFromPrimary(),
2222
pinRemindersEnabled = SignalStore.pinValues().arePinRemindersEnabled(),
2323
registrationLockEnabled = SignalStore.svr().isRegistrationLockEnabled,
2424
userUnregistered = TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication()),

app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/ChatsSettingsFragment.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import org.thoughtcrime.securesms.components.settings.DSLConfiguration
77
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
88
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
99
import org.thoughtcrime.securesms.components.settings.configure
10+
import org.thoughtcrime.securesms.keyvalue.SignalStore
1011
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
1112
import org.thoughtcrime.securesms.util.navigation.safeNavigate
1213

@@ -33,11 +34,18 @@ class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__ch
3334
title = DSLSettingsText.from(R.string.preferences__generate_link_previews),
3435
summary = DSLSettingsText.from(R.string.preferences__retrieve_link_previews_from_websites_for_messages),
3536
isChecked = state.generateLinkPreviews,
37+
isEnabled = SignalStore.account().isPrimaryDevice,
3638
onClick = {
3739
viewModel.setGenerateLinkPreviewsEnabled(!state.generateLinkPreviews)
3840
}
3941
)
4042

43+
if (SignalStore.account().isLinkedDevice) {
44+
textPref(
45+
summary = DSLSettingsText.from(R.string.preferences__primary_only)
46+
)
47+
}
48+
4149
switchPref(
4250
title = DSLSettingsText.from(R.string.preferences__pref_use_address_book_photos),
4351
summary = DSLSettingsText.from(R.string.preferences__display_contact_photos_from_your_address_book_if_available),

app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/ChatsSettingsViewModel.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ class ChatsSettingsViewModel @JvmOverloads constructor(
3535
}
3636

3737
fun setGenerateLinkPreviewsEnabled(enabled: Boolean) {
38+
if (SignalStore.account().isLinkedDevice) {
39+
return
40+
}
3841
store.update { it.copy(generateLinkPreviews = enabled) }
3942
SignalStore.settings().isLinkPreviewsEnabled = enabled
4043
repository.syncLinkPreviewsState()

app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsFragment.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsText
3030
import org.thoughtcrime.securesms.components.settings.PreferenceModel
3131
import org.thoughtcrime.securesms.components.settings.PreferenceViewHolder
3232
import org.thoughtcrime.securesms.components.settings.configure
33+
import org.thoughtcrime.securesms.keyvalue.SignalStore
3334
import org.thoughtcrime.securesms.preferences.widgets.PassphraseLockTriggerPreference
3435
import org.thoughtcrime.securesms.util.CommunicationActions
3536
import org.thoughtcrime.securesms.util.ConversationUtil
@@ -189,6 +190,7 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac
189190
title = DSLSettingsText.from(R.string.preferences__read_receipts),
190191
summary = DSLSettingsText.from(R.string.preferences__if_read_receipts_are_disabled_you_wont_be_able_to_see_read_receipts),
191192
isChecked = state.readReceipts,
193+
isEnabled = SignalStore.account().isPrimaryDevice,
192194
onClick = {
193195
viewModel.setReadReceiptsEnabled(!state.readReceipts)
194196
}
@@ -198,11 +200,18 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac
198200
title = DSLSettingsText.from(R.string.preferences__typing_indicators),
199201
summary = DSLSettingsText.from(R.string.preferences__if_typing_indicators_are_disabled_you_wont_be_able_to_see_typing_indicators),
200202
isChecked = state.typingIndicators,
203+
isEnabled = SignalStore.account().isPrimaryDevice,
201204
onClick = {
202205
viewModel.setTypingIndicatorsEnabled(!state.typingIndicators)
203206
}
204207
)
205208

209+
if (SignalStore.account().isLinkedDevice) {
210+
textPref(
211+
summary = DSLSettingsText.from(R.string.preferences__primary_only)
212+
)
213+
}
214+
206215
dividerPref()
207216

208217
sectionHeaderPref(R.string.PrivacySettingsFragment__disappearing_messages)

app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsViewModel.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,18 @@ class PrivacySettingsViewModel(
3535
}
3636

3737
fun setReadReceiptsEnabled(enabled: Boolean) {
38+
if (SignalStore.account().isLinkedDevice) {
39+
return
40+
}
3841
sharedPreferences.edit().putBoolean(TextSecurePreferences.READ_RECEIPTS_PREF, enabled).apply()
3942
repository.syncReadReceiptState()
4043
refresh()
4144
}
4245

4346
fun setTypingIndicatorsEnabled(enabled: Boolean) {
47+
if (SignalStore.account().isLinkedDevice) {
48+
return
49+
}
4450
sharedPreferences.edit().putBoolean(TextSecurePreferences.TYPING_INDICATORS, enabled).apply()
4551
repository.syncTypingIndicatorsState()
4652
refresh()

app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/advanced/AdvancedPrivacySettingsFragment.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,18 @@ class AdvancedPrivacySettingsFragment : DSLSettingsFragment(R.string.preferences
183183
.append(statusIcon)
184184
),
185185
summary = DSLSettingsText.from(R.string.AdvancedPrivacySettingsFragment__show_an_icon),
186-
isChecked = state.showSealedSenderStatusIcon
186+
isChecked = state.showSealedSenderStatusIcon,
187+
isEnabled = SignalStore.account().isPrimaryDevice
187188
) {
188189
viewModel.setShowStatusIconForSealedSender(!state.showSealedSenderStatusIcon)
189190
}
190191

192+
if (SignalStore.account().isLinkedDevice) {
193+
textPref(
194+
summary = DSLSettingsText.from(R.string.preferences__primary_only)
195+
)
196+
}
197+
191198
switchPref(
192199
title = DSLSettingsText.from(R.string.preferences_communication__sealed_sender_allow_from_anyone),
193200
summary = DSLSettingsText.from(R.string.preferences_communication__sealed_sender_allow_from_anyone_description),

app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/advanced/AdvancedPrivacySettingsViewModel.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ class AdvancedPrivacySettingsViewModel(
6363
}
6464

6565
fun setShowStatusIconForSealedSender(enabled: Boolean) {
66+
if (SignalStore.account().isLinkedDevice) {
67+
return
68+
}
6669
sharedPreferences.edit().putBoolean(TextSecurePreferences.SHOW_UNIDENTIFIED_DELIVERY_INDICATORS, enabled).apply()
6770
repository.syncShowSealedSenderIconState()
6871
refresh()

0 commit comments

Comments
 (0)