mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-23 18:15:22 +00:00
Merge branch 'dev' into sealed-sender
This commit is contained in:
commit
8aa46aebec
@ -178,8 +178,6 @@
|
||||
android:name="org.thoughtcrime.securesms.loki.redesign.activities.LinkedDevicesActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
<!-- Session -->
|
||||
<activity android:name="org.thoughtcrime.securesms.loki.LinkedDevicesActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.WebRtcCallActivity"
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|fontScale"
|
||||
@ -549,27 +547,7 @@
|
||||
android:name="org.thoughtcrime.securesms.ShortcutLauncherActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:exported="true"
|
||||
android:theme="@style/TextSecure.LightNoActionBar" /> <!-- Loki -->
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.loki.DisplayNameActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/TextSecure.DarkRegistrationTheme"
|
||||
android:windowSoftInputMode="stateUnchanged" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.loki.SeedActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/TextSecure.DarkRegistrationTheme"
|
||||
android:windowSoftInputMode="stateUnchanged" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.loki.NewConversationActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:windowSoftInputMode="stateAlwaysVisible" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.loki.AddPublicChatActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:windowSoftInputMode="stateAlwaysVisible" /> <!-- Loki -->
|
||||
android:theme="@style/TextSecure.LightNoActionBar" />
|
||||
<service
|
||||
android:name="org.thoughtcrime.securesms.service.WebRtcCallService"
|
||||
android:enabled="true" />
|
||||
@ -808,12 +786,12 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<!-- Session -->
|
||||
<receiver android:name="org.thoughtcrime.securesms.loki.BackgroundPollWorker">
|
||||
<receiver android:name="org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPollWorker">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name="org.thoughtcrime.securesms.loki.BackgroundPublicChatPollWorker">
|
||||
<receiver android:name="org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPublicChatPollWorker">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
|
@ -187,7 +187,6 @@ dependencies {
|
||||
implementation "org.whispersystems:curve25519-java:0.5.0"
|
||||
// Remote:
|
||||
// implementation "com.github.loki-project:loki-messenger-android-service:dev-SNAPSHOT"
|
||||
// implementation "org.signal:signal-metadata-android:0.0.3"
|
||||
implementation "com.google.protobuf:protobuf-java:2.5.0"
|
||||
implementation "com.googlecode.libphonenumber:libphonenumber:8.10.7"
|
||||
implementation "com.fasterxml.jackson.core:jackson-databind:2.9.8"
|
||||
|
@ -66,8 +66,8 @@ import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.logging.PersistentLogger;
|
||||
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
|
||||
import org.thoughtcrime.securesms.loki.BackgroundPollWorker;
|
||||
import org.thoughtcrime.securesms.loki.BackgroundPublicChatPollWorker;
|
||||
import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPollWorker;
|
||||
import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPublicChatPollWorker;
|
||||
import org.thoughtcrime.securesms.loki.LokiAPIDatabase;
|
||||
import org.thoughtcrime.securesms.loki.LokiPublicChatManager;
|
||||
import org.thoughtcrime.securesms.loki.LokiRSSFeedPoller;
|
||||
|
@ -41,8 +41,6 @@ import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||
import org.thoughtcrime.securesms.loki.LinkedDevicesActivity;
|
||||
import org.thoughtcrime.securesms.loki.QRCodeDialog;
|
||||
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
|
||||
@ -338,13 +336,8 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
shareIntent.setType("text/plain");
|
||||
startActivity(shareIntent);
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_QR_CODE:
|
||||
QRCodeDialog.INSTANCE.show(getContext());
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_LINKED_DEVICES:
|
||||
Intent intent = new Intent(getActivity(), LinkedDevicesActivity.class);
|
||||
startActivity(intent);
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_QR_CODE: break;
|
||||
case PREFERENCE_CATEGORY_LINKED_DEVICES: break;
|
||||
case PREFERENCE_CATEGORY_SEED:
|
||||
Analytics.Companion.getShared().track("Seed Modal Shown");
|
||||
File languageFileDirectory = new File(getContext().getApplicationInfo().dataDir);
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
@ -35,7 +34,6 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
@ -46,20 +44,16 @@ import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.thoughtcrime.securesms.components.RatingManager;
|
||||
import org.thoughtcrime.securesms.components.SearchToolbar;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationActivity;
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
|
||||
import org.thoughtcrime.securesms.loki.AddPublicChatActivity;
|
||||
import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable;
|
||||
import org.thoughtcrime.securesms.loki.RecipientAvatarModifiedEvent;
|
||||
import org.thoughtcrime.securesms.loki.redesign.activities.JoinPublicChatActivity;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.search.SearchFragment;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
@ -68,7 +62,6 @@ import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -333,7 +326,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
}
|
||||
|
||||
private void addNewPublicChat() {
|
||||
startActivity(new Intent(this, AddPublicChatActivity.class));
|
||||
startActivity(new Intent(this, JoinPublicChatActivity.class));
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
@ -74,7 +74,7 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||
import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
|
||||
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
|
||||
import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob;
|
||||
import org.thoughtcrime.securesms.loki.NewConversationActivity;
|
||||
import org.thoughtcrime.securesms.loki.redesign.activities.CreatePrivateChatActivity;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
@ -155,7 +155,7 @@ public class ConversationListFragment extends Fragment
|
||||
super.onActivityCreated(bundle);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
fab.setOnClickListener(v -> startActivity(new Intent(getActivity(), NewConversationActivity.class)));
|
||||
fab.setOnClickListener(v -> startActivity(new Intent(getActivity(), CreatePrivateChatActivity.class)));
|
||||
initializeListAdapter();
|
||||
initializeTypingObserver();
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ import org.thoughtcrime.securesms.components.FromTextView;
|
||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||
import org.thoughtcrime.securesms.components.TypingIndicatorView;
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
import org.thoughtcrime.securesms.loki.LokiAPIUtilities;
|
||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities;
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MentionUtilities;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
@ -26,7 +26,7 @@ import org.thoughtcrime.securesms.database.loaders.DeviceListLoader;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.devicelist.Device;
|
||||
import org.thoughtcrime.securesms.loki.DeviceListBottomSheetFragment;
|
||||
import org.thoughtcrime.securesms.loki.MnemonicUtilities;
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.whispersystems.libsignal.util.guava.Function;
|
||||
|
@ -15,7 +15,7 @@ import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity;
|
||||
import org.thoughtcrime.securesms.loki.redesign.activities.LandingActivity;
|
||||
import org.thoughtcrime.securesms.loki.SeedActivity;
|
||||
import org.thoughtcrime.securesms.loki.redesign.activities.SeedActivity;
|
||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
@ -13,7 +13,6 @@ import org.thoughtcrime.securesms.conversation.ConversationActivity;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.NewConversationActivity;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Rfc5724Uri;
|
||||
|
||||
|
@ -157,7 +157,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.LokiAPIUtilities;
|
||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities;
|
||||
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
|
||||
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
|
||||
import org.thoughtcrime.securesms.loki.LokiThreadDatabaseDelegate;
|
||||
|
@ -2,47 +2,23 @@ package org.thoughtcrime.securesms.database.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||
import org.thoughtcrime.securesms.database.Database;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.devicelist.Device;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.MnemonicUtilities;
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities;
|
||||
import org.thoughtcrime.securesms.util.AsyncLoader;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
import org.whispersystems.libsignal.ecc.Curve;
|
||||
import org.whispersystems.libsignal.ecc.ECPrivateKey;
|
||||
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
||||
import org.whispersystems.libsignal.util.ByteUtil;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
|
||||
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.*;
|
||||
import static org.whispersystems.signalservice.loki.utilities.TrimmingKt.removing05PrefixIfNeeded;
|
||||
|
||||
public class DeviceListLoader extends AsyncLoader<List<Device>> {
|
||||
|
||||
private static final String TAG = DeviceListLoader.class.getSimpleName();
|
||||
|
@ -68,7 +68,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.FriendRequestHandler;
|
||||
import org.thoughtcrime.securesms.loki.LokiAPIUtilities;
|
||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities;
|
||||
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
|
||||
import org.thoughtcrime.securesms.loki.LokiPreKeyBundleDatabase;
|
||||
import org.thoughtcrime.securesms.loki.LokiPreKeyRecordDatabase;
|
||||
|
@ -1,78 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Patterns
|
||||
import android.view.MenuItem
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_add_public_chat.*
|
||||
import network.loki.messenger.R
|
||||
import nl.komponents.kovenant.ui.failUi
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
|
||||
class AddPublicChatActivity : PassphraseRequiredActionBarActivity() {
|
||||
private val dynamicTheme = DynamicTheme()
|
||||
|
||||
override fun onPreCreate() {
|
||||
dynamicTheme.onCreate(this)
|
||||
}
|
||||
|
||||
override fun onCreate(bundle: Bundle?, isReady: Boolean) {
|
||||
supportActionBar!!.setTitle(R.string.fragment_add_public_chat_title)
|
||||
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||
setContentView(R.layout.activity_add_public_chat)
|
||||
updateUI(false)
|
||||
addButton.setOnClickListener { addPublicChatIfPossible() }
|
||||
}
|
||||
|
||||
public override fun onResume() {
|
||||
super.onResume()
|
||||
dynamicTheme.onResume(this)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == android.R.id.home) {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun addPublicChatIfPossible() {
|
||||
val inputMethodManager = getSystemService(BaseActionBarActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.hideSoftInputFromWindow(urlEditText.windowToken, 0)
|
||||
val url = urlEditText.text.toString().toLowerCase().replace("http://", "https://")
|
||||
if (!Patterns.WEB_URL.matcher(url).matches() || !url.startsWith("https://")) {
|
||||
return Toast.makeText(this, R.string.fragment_add_public_chat_invalid_url_message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
updateUI(true)
|
||||
val application = ApplicationContext.getInstance(this)
|
||||
val channel: Long = 1
|
||||
val displayName = TextSecurePreferences.getProfileName(this)
|
||||
val lokiPublicChatAPI = application.lokiPublicChatAPI!!
|
||||
application.lokiPublicChatManager.addChat(url, channel).successUi {
|
||||
lokiPublicChatAPI.getMessages(channel, url)
|
||||
lokiPublicChatAPI.setDisplayName(displayName, url)
|
||||
val profileKey: ByteArray = ProfileKeyUtil.getProfileKey(this)
|
||||
val profileUrl: String? = TextSecurePreferences.getProfileAvatarUrl(this)
|
||||
lokiPublicChatAPI.setProfilePicture(url, profileKey, profileUrl)
|
||||
finish()
|
||||
}.failUi {
|
||||
updateUI(false)
|
||||
Toast.makeText(this, R.string.fragment_add_public_chat_connection_failed_message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateUI(isConnecting: Boolean) {
|
||||
addButton.isEnabled = !isConnecting
|
||||
val text = if (isConnecting) R.string.fragment_add_public_chat_add_button_title_2 else R.string.fragment_add_public_chat_add_button_title_1
|
||||
addButton.setText(text)
|
||||
urlEditText.isEnabled = !isConnecting
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import org.whispersystems.signalservice.loki.api.PairingAuthorisation
|
||||
|
||||
// Loki - TODO: Remove this yucky delegate pattern for device linking dialog once we have the redesign
|
||||
interface DeviceLinkingDelegate {
|
||||
companion object {
|
||||
fun combine(vararg delegates: DeviceLinkingDelegate?): DeviceLinkingDelegate {
|
||||
val validDelegates = delegates.filterNotNull()
|
||||
return object : DeviceLinkingDelegate {
|
||||
override fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) {
|
||||
for (delegate in validDelegates) { delegate.handleDeviceLinkAuthorized(pairingAuthorisation) }
|
||||
}
|
||||
|
||||
override fun handleDeviceLinkingDialogDismissed() {
|
||||
for (delegate in validDelegates) { delegate.handleDeviceLinkingDialogDismissed() }
|
||||
}
|
||||
|
||||
override fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) {
|
||||
for (delegate in validDelegates) { delegate.sendPairingAuthorizedMessage(pairingAuthorisation) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) {}
|
||||
fun handleDeviceLinkingDialogDismissed() {}
|
||||
fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) {}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.Context
|
||||
import android.support.v7.app.AlertDialog
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLinkingSession
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLinkingSessionListener
|
||||
import org.whispersystems.signalservice.loki.api.PairingAuthorisation
|
||||
|
||||
class DeviceLinkingDialog private constructor(private val context: Context, private val mode: DeviceLinkingView.Mode, private val delegate: DeviceLinkingDelegate?) : DeviceLinkingDelegate, DeviceLinkingSessionListener {
|
||||
private lateinit var view: DeviceLinkingView
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
companion object {
|
||||
fun show(context: Context, mode: DeviceLinkingView.Mode, delegate: DeviceLinkingDelegate?): DeviceLinkingDialog {
|
||||
val dialog = DeviceLinkingDialog(context, mode, delegate)
|
||||
dialog.show()
|
||||
return dialog
|
||||
}
|
||||
}
|
||||
|
||||
private fun show() {
|
||||
val delegate = DeviceLinkingDelegate.combine(this, this.delegate)
|
||||
view = DeviceLinkingView(context, mode, delegate)
|
||||
dialog = AlertDialog.Builder(context).setView(view).show()
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
view.dismiss = { dismiss() }
|
||||
DeviceLinkingSession.shared.startListeningForLinkingRequests()
|
||||
DeviceLinkingSession.shared.addListener(this)
|
||||
}
|
||||
|
||||
private fun dismiss() {
|
||||
DeviceLinkingSession.shared.stopListeningForLinkingRequests()
|
||||
DeviceLinkingSession.shared.removeListener(this)
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
override fun handleDeviceLinkingDialogDismissed() {
|
||||
if (mode == DeviceLinkingView.Mode.Master && view.pairingAuthorisation != null) {
|
||||
val authorisation = view.pairingAuthorisation!!
|
||||
DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(authorisation.secondaryDevicePublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
override fun requestUserAuthorization(authorisation: PairingAuthorisation) {
|
||||
Util.runOnMain {
|
||||
view.requestUserAuthorization(authorisation)
|
||||
}
|
||||
DeviceLinkingSession.shared.stopListeningForLinkingRequests()
|
||||
}
|
||||
|
||||
override fun onDeviceLinkRequestAuthorized(authorisation: PairingAuthorisation) {
|
||||
Util.runOnMain {
|
||||
view.onDeviceLinkAuthorized(authorisation)
|
||||
}
|
||||
DeviceLinkingSession.shared.stopListeningForLinkingRequests()
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.PorterDuff
|
||||
import android.os.Handler
|
||||
import android.util.AttributeSet
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.view_device_linking.view.*
|
||||
import kotlinx.android.synthetic.main.view_device_linking.view.cancelButton
|
||||
import kotlinx.android.synthetic.main.view_device_linking.view.explanationTextView
|
||||
import kotlinx.android.synthetic.main.view_device_linking.view.titleTextView
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.qr.QrCode
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.loki.api.PairingAuthorisation
|
||||
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec
|
||||
import java.io.File
|
||||
|
||||
class DeviceLinkingView private constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, private val mode: Mode, private var delegate: DeviceLinkingDelegate) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
private val languageFileDirectory: File = MnemonicUtilities.getLanguageFileDirectory(context)
|
||||
var dismiss: (() -> Unit)? = null
|
||||
var pairingAuthorisation: PairingAuthorisation? = null
|
||||
private set
|
||||
|
||||
// region Types
|
||||
enum class Mode { Master, Slave }
|
||||
// endregion
|
||||
|
||||
// region Lifecycle
|
||||
constructor(context: Context, mode: Mode, delegate: DeviceLinkingDelegate) : this(context, null, 0, mode, delegate)
|
||||
private constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0, Mode.Master, object : DeviceLinkingDelegate { }) // Just pass in a dummy mode
|
||||
private constructor(context: Context) : this(context, null)
|
||||
|
||||
init {
|
||||
setUpViewHierarchy()
|
||||
}
|
||||
|
||||
private fun setUpViewHierarchy() {
|
||||
inflate(context, R.layout.view_device_linking, this)
|
||||
spinner.indeterminateDrawable.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)
|
||||
val titleID = when (mode) {
|
||||
Mode.Master -> R.string.view_device_linking_title_1
|
||||
Mode.Slave -> R.string.view_device_linking_title_2
|
||||
}
|
||||
titleTextView.text = resources.getString(titleID)
|
||||
val explanationID = when (mode) {
|
||||
Mode.Master -> R.string.view_device_linking_explanation_1
|
||||
Mode.Slave -> R.string.view_device_linking_explanation_2
|
||||
}
|
||||
explanationTextView.text = resources.getString(explanationID)
|
||||
mnemonicTextView.visibility = if (mode == Mode.Master) View.GONE else View.VISIBLE
|
||||
if (mode == Mode.Slave) {
|
||||
val hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
mnemonicTextView.text = MnemonicUtilities.getFirst3Words(MnemonicCodec(languageFileDirectory), hexEncodedPublicKey)
|
||||
}
|
||||
authorizeButton.visibility = View.GONE
|
||||
authorizeButton.setOnClickListener { authorizePairing() }
|
||||
|
||||
// QR Code
|
||||
spinner.visibility = if (mode == Mode.Master) View.GONE else View.VISIBLE
|
||||
qrCodeImageView.visibility = if (mode == Mode.Master) View.VISIBLE else View.GONE
|
||||
if (mode == Mode.Master) {
|
||||
val hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
val displayMetrics = DisplayMetrics()
|
||||
ServiceUtil.getWindowManager(context).defaultDisplay.getMetrics(displayMetrics)
|
||||
val size = displayMetrics.widthPixels - 2 * toPx(96, resources)
|
||||
val qrCode = QrCode.create(hexEncodedPublicKey, size)
|
||||
qrCodeImageView.setImageBitmap(qrCode)
|
||||
}
|
||||
|
||||
cancelButton.setOnClickListener { cancel() }
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Device Linking
|
||||
fun requestUserAuthorization(pairingAuthorisation: PairingAuthorisation) {
|
||||
if (mode != Mode.Master || pairingAuthorisation.type != PairingAuthorisation.Type.REQUEST || this.pairingAuthorisation != null) { return }
|
||||
this.pairingAuthorisation = pairingAuthorisation
|
||||
spinner.visibility = View.GONE
|
||||
qrCodeImageView.visibility = View.GONE
|
||||
val titleTextViewLayoutParams = titleTextView.layoutParams as LayoutParams
|
||||
titleTextViewLayoutParams.topMargin = toPx(16, resources)
|
||||
titleTextView.layoutParams = titleTextViewLayoutParams
|
||||
titleTextView.text = resources.getString(R.string.view_device_linking_title_3)
|
||||
explanationTextView.text = resources.getString(R.string.view_device_linking_explanation_2)
|
||||
mnemonicTextView.visibility = View.VISIBLE
|
||||
mnemonicTextView.text = MnemonicUtilities.getFirst3Words(MnemonicCodec(languageFileDirectory), pairingAuthorisation.secondaryDevicePublicKey)
|
||||
authorizeButton.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun onDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) {
|
||||
if (mode != Mode.Slave || pairingAuthorisation.type != PairingAuthorisation.Type.GRANT || this.pairingAuthorisation != null) { return }
|
||||
this.pairingAuthorisation = pairingAuthorisation
|
||||
spinner.visibility = View.GONE
|
||||
val titleTextViewLayoutParams = titleTextView.layoutParams as LayoutParams
|
||||
titleTextViewLayoutParams.topMargin = toPx(8, resources)
|
||||
titleTextView.layoutParams = titleTextViewLayoutParams
|
||||
titleTextView.text = resources.getString(R.string.view_device_linking_title_4)
|
||||
val explanationTextViewLayoutParams = explanationTextView.layoutParams as LayoutParams
|
||||
explanationTextViewLayoutParams.bottomMargin = toPx(12, resources)
|
||||
explanationTextView.layoutParams = explanationTextViewLayoutParams
|
||||
explanationTextView.text = resources.getString(R.string.view_device_linking_explanation_3)
|
||||
titleTextView.text = resources.getString(R.string.view_device_linking_title_4)
|
||||
mnemonicTextView.visibility = View.GONE
|
||||
buttonContainer.visibility = View.GONE
|
||||
cancelButton.visibility = View.GONE
|
||||
Handler().postDelayed({
|
||||
delegate.handleDeviceLinkAuthorized(pairingAuthorisation)
|
||||
dismiss?.invoke()
|
||||
}, 4000)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Interaction
|
||||
private fun authorizePairing() {
|
||||
val pairingAuthorisation = this.pairingAuthorisation
|
||||
if (mode != Mode.Master || pairingAuthorisation == null) { return; }
|
||||
delegate.sendPairingAuthorizedMessage(pairingAuthorisation)
|
||||
delegate.handleDeviceLinkAuthorized(pairingAuthorisation)
|
||||
dismiss?.invoke()
|
||||
}
|
||||
|
||||
private fun cancel() {
|
||||
delegate.handleDeviceLinkingDialogDismissed()
|
||||
dismiss?.invoke()
|
||||
}
|
||||
// endregion
|
||||
}
|
@ -9,16 +9,16 @@ import kotlinx.android.synthetic.main.fragment_device_list_bottom_sheet.*
|
||||
import network.loki.messenger.R
|
||||
|
||||
public class DeviceListBottomSheetFragment : BottomSheetDialogFragment() {
|
||||
var onEditTapped: (() -> Unit)? = null
|
||||
var onUnlinkTapped: (() -> Unit)? = null
|
||||
var onEditTapped: (() -> Unit)? = null
|
||||
var onUnlinkTapped: (() -> Unit)? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_device_list_bottom_sheet, container, false)
|
||||
}
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_device_list_bottom_sheet, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
editDisplayNameText.setOnClickListener { onEditTapped?.invoke() }
|
||||
unlinkDeviceText.setOnClickListener { onUnlinkTapped?.invoke() }
|
||||
}
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
editDisplayNameText.setOnClickListener { onEditTapped?.invoke() }
|
||||
unlinkDeviceText.setOnClickListener { onUnlinkTapped?.invoke() }
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import kotlinx.android.synthetic.main.activity_display_name.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
import org.thoughtcrime.securesms.ConversationListActivity
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.show
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipher
|
||||
import org.whispersystems.signalservice.loki.utilities.Analytics
|
||||
|
||||
class DisplayNameActivity : BaseActionBarActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_display_name)
|
||||
nextButton.setOnClickListener { continueIfPossible() }
|
||||
Analytics.shared.track("Display Name Screen Viewed")
|
||||
}
|
||||
|
||||
private fun continueIfPossible() {
|
||||
val name = nameEditText.text.toString()
|
||||
if (name.isEmpty()) {
|
||||
return nameEditText.input.setError("Invalid")
|
||||
}
|
||||
if (!name.matches(Regex("[a-zA-Z0-9_]+"))) {
|
||||
return nameEditText.input.setError("Invalid (a-z, A-Z, 0-9 and _ only)")
|
||||
}
|
||||
if (name.toByteArray().size > ProfileCipher.NAME_PADDED_LENGTH) {
|
||||
return nameEditText.input.setError("Too Long")
|
||||
} else {
|
||||
Analytics.shared.track("Display Name Updated")
|
||||
TextSecurePreferences.setProfileName(this, name)
|
||||
}
|
||||
val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.hideSoftInputFromWindow(nameEditText.windowToken, 0)
|
||||
TextSecurePreferences.setHasSeenWelcomeScreen(this, true)
|
||||
TextSecurePreferences.setPromptedPushRegistration(this, true)
|
||||
val application = ApplicationContext.getInstance(this)
|
||||
application.setUpP2PAPI()
|
||||
application.startLongPollingIfNeeded()
|
||||
application.setUpStorageAPIIfNeeded()
|
||||
show(Intent(this, ConversationListActivity::class.java))
|
||||
finish()
|
||||
val publicChatAPI = ApplicationContext.getInstance(this).lokiPublicChatAPI
|
||||
if (publicChatAPI != null) {
|
||||
application.createDefaultPublicChatsIfNeeded()
|
||||
application.createRSSFeedsIfNeeded()
|
||||
application.lokiPublicChatManager.startPollersIfNeeded()
|
||||
application.startRSSFeedPollersIfNeeded()
|
||||
val servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers()
|
||||
servers.forEach { publicChatAPI.setDisplayName(name, it) }
|
||||
application.updatePublicChatProfileAvatarIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import org.thoughtcrime.securesms.*
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage
|
||||
import network.loki.messenger.R
|
||||
import nl.komponents.kovenant.then
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.sms.MessageSender
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.whispersystems.signalservice.loki.api.LokiStorageAPI
|
||||
import org.whispersystems.signalservice.loki.api.PairingAuthorisation
|
||||
|
||||
class LinkedDevicesActivity : PassphraseRequiredActionBarActivity(), DeviceLinkingDelegate {
|
||||
|
||||
companion object {
|
||||
private val TAG = DeviceActivity::class.java.simpleName
|
||||
}
|
||||
|
||||
private val dynamicTheme = DynamicTheme()
|
||||
private val dynamicLanguage = DynamicLanguage()
|
||||
private lateinit var deviceListFragment: DeviceListFragment
|
||||
|
||||
public override fun onPreCreate() {
|
||||
dynamicTheme.onCreate(this)
|
||||
dynamicLanguage.onCreate(this)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
|
||||
super.onCreate(savedInstanceState, ready)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar?.setTitle(R.string.AndroidManifest__linked_devices)
|
||||
this.deviceListFragment = DeviceListFragment()
|
||||
this.deviceListFragment.setAddDeviceButtonListener {
|
||||
DeviceLinkingDialog.show(this, DeviceLinkingView.Mode.Master, this)
|
||||
}
|
||||
this.deviceListFragment.setHandleDisconnectDevice { devicePublicKey ->
|
||||
// Purge the device pairing from our database
|
||||
val ourPublicKey = TextSecurePreferences.getLocalNumber(this)
|
||||
val database = DatabaseFactory.getLokiAPIDatabase(this)
|
||||
database.removePairingAuthorisation(ourPublicKey, devicePublicKey)
|
||||
// Update mapping on the file server
|
||||
LokiStorageAPI.shared.updateUserDeviceMappings().success {
|
||||
// Send an unpair request to let the device know that it has been revoked
|
||||
MessageSender.sendUnpairRequest(this, devicePublicKey)
|
||||
}
|
||||
// Refresh the list
|
||||
this.deviceListFragment.refresh()
|
||||
Toast.makeText(this, R.string.DeviceListActivity_unlinked_device, Toast.LENGTH_LONG).show()
|
||||
return@setHandleDisconnectDevice null
|
||||
}
|
||||
this.deviceListFragment.setHandleDeviceNameChange { pair ->
|
||||
DatabaseFactory.getLokiUserDatabase(this).setDisplayName(pair.first, pair.second)
|
||||
this.deviceListFragment.refresh()
|
||||
return@setHandleDeviceNameChange null
|
||||
}
|
||||
initFragment(android.R.id.content, deviceListFragment, dynamicLanguage.currentLocale)
|
||||
}
|
||||
|
||||
public override fun onResume() {
|
||||
super.onResume()
|
||||
dynamicTheme.onResume(this)
|
||||
dynamicLanguage.onResume(this)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == android.R.id.home) {
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) {
|
||||
AsyncTask.execute {
|
||||
signAndSendPairingAuthorisationMessage(this, pairingAuthorisation)
|
||||
Util.runOnMain { this.deviceListFragment.refresh() }
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import org.thoughtcrime.securesms.database.Database
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.*
|
||||
import org.thoughtcrime.securesms.util.Base64
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol
|
||||
|
@ -6,6 +6,9 @@ import org.thoughtcrime.securesms.database.Address
|
||||
import org.thoughtcrime.securesms.database.Database
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.get
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.getInt
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.insertOrUpdate
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiMessageDatabaseProtocol
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus
|
||||
|
||||
|
@ -9,6 +9,10 @@ import org.thoughtcrime.securesms.database.Database
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.logging.Log
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.get
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.getBase64EncodedData
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.getInt
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.insertOrUpdate
|
||||
import org.thoughtcrime.securesms.util.Base64
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.libsignal.IdentityKey
|
||||
|
@ -5,6 +5,9 @@ import android.content.Context
|
||||
import org.thoughtcrime.securesms.crypto.PreKeyUtil
|
||||
import org.thoughtcrime.securesms.database.Database
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.get
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.getInt
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.insertOrUpdate
|
||||
import org.whispersystems.libsignal.state.PreKeyRecord
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiPreKeyRecordDatabaseProtocol
|
||||
|
||||
|
@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.database.DatabaseContentProviders
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.groups.GroupManager
|
||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPublicChatPoller
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.whispersystems.signalservice.loki.api.LokiPublicChat
|
||||
|
@ -7,6 +7,11 @@ import org.thoughtcrime.securesms.database.Address
|
||||
import org.thoughtcrime.securesms.database.Database
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.get
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.getInt
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.getLong
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.getString
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.insertOrUpdate
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.internal.util.JsonUtil
|
||||
|
@ -7,6 +7,8 @@ import android.util.Log
|
||||
import org.thoughtcrime.securesms.database.Address
|
||||
import org.thoughtcrime.securesms.database.Database
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.get
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.insertOrUpdate
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiUserDatabaseProtocol
|
||||
|
@ -1,85 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.conversation.ConversationActivity
|
||||
import org.thoughtcrime.securesms.database.Address
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.qr.ScanListener
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.loki.utilities.Analytics
|
||||
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
|
||||
|
||||
class NewConversationActivity : PassphraseRequiredActionBarActivity(), ScanListener {
|
||||
private val dynamicTheme = DynamicTheme()
|
||||
|
||||
override fun onPreCreate() {
|
||||
dynamicTheme.onCreate(this)
|
||||
}
|
||||
|
||||
override fun onCreate(bundle: Bundle?, isReady: Boolean) {
|
||||
supportActionBar!!.setTitle(R.string.fragment_new_conversation_title)
|
||||
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||
val fragment = NewConversationFragment()
|
||||
initFragment(android.R.id.content, fragment, null)
|
||||
}
|
||||
|
||||
public override fun onResume() {
|
||||
super.onResume()
|
||||
dynamicTheme.onResume(this)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == android.R.id.home) {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
fun scanQRCode() {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.ifNecessary()
|
||||
.withPermanentDenialDialog(getString(R.string.fragment_scan_qr_code_camera_permission_dialog_message))
|
||||
.onAllGranted {
|
||||
val fragment = ScanQRCodeFragment()
|
||||
fragment.scanListener = this
|
||||
supportFragmentManager.beginTransaction().replace(android.R.id.content, fragment).addToBackStack(null).commitAllowingStateLoss()
|
||||
}
|
||||
.onAnyDenied { Toast.makeText(this, R.string.fragment_scan_qr_code_camera_permission_dialog_message, Toast.LENGTH_SHORT).show() }
|
||||
.execute()
|
||||
}
|
||||
|
||||
override fun onQrDataFound(hexEncodedPublicKey: String) {
|
||||
Analytics.shared.track("QR Code Scanned")
|
||||
startNewConversationIfPossible(hexEncodedPublicKey)
|
||||
}
|
||||
|
||||
fun startNewConversationIfPossible(hexEncodedPublicKey: String) {
|
||||
if (!PublicKeyValidation.isValid(hexEncodedPublicKey)) { return Toast.makeText(this, R.string.fragment_new_conversation_invalid_public_key_message, Toast.LENGTH_SHORT).show() }
|
||||
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this)
|
||||
// If we try to contact our master device then redirect to note to self
|
||||
val contactPublicKey = if (TextSecurePreferences.getMasterHexEncodedPublicKey(this) == hexEncodedPublicKey) userHexEncodedPublicKey else hexEncodedPublicKey
|
||||
val contact = Recipient.from(this, Address.fromSerialized(contactPublicKey), true)
|
||||
val intent = Intent(this, ConversationActivity::class.java)
|
||||
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, contact.address)
|
||||
intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA))
|
||||
intent.setDataAndType(getIntent().data, getIntent().type)
|
||||
val existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(contact)
|
||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, existingThread)
|
||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT)
|
||||
Analytics.shared.track("New Conversation Started")
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import kotlinx.android.synthetic.main.fragment_new_conversation.*
|
||||
import network.loki.messenger.R
|
||||
|
||||
class NewConversationFragment : Fragment() {
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_new_conversation, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
qrCodeButton.setOnClickListener {
|
||||
val activity = activity as NewConversationActivity
|
||||
activity.scanQRCode()
|
||||
}
|
||||
nextButton.setOnClickListener {
|
||||
val activity = activity as NewConversationActivity
|
||||
val hexEncodedPublicKey = publicKeyEditText.text.toString().trim()
|
||||
activity.startNewConversationIfPossible(hexEncodedPublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val activity = activity as NewConversationActivity
|
||||
activity.supportActionBar!!.setTitle(R.string.fragment_new_conversation_title)
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.Context
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.util.AttributeSet
|
||||
import android.util.DisplayMetrics
|
||||
import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.view_qr_code.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.qr.QrCode
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
|
||||
object QRCodeDialog {
|
||||
|
||||
fun show(context: Context) {
|
||||
val view = QRCodeView(context)
|
||||
val dialog = AlertDialog.Builder(context).setView(view).show()
|
||||
view.onCancel = { dialog.dismiss() }
|
||||
}
|
||||
}
|
||||
|
||||
class QRCodeView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
var onCancel: (() -> Unit)? = null
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
||||
constructor(context: Context) : this(context, null)
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.view_qr_code, this)
|
||||
val hexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(getContext()) ?: TextSecurePreferences.getLocalNumber(context)
|
||||
val displayMetrics = DisplayMetrics()
|
||||
ServiceUtil.getWindowManager(context).defaultDisplay.getMetrics(displayMetrics)
|
||||
val size = displayMetrics.widthPixels - 2 * toPx(96, resources)
|
||||
val qrCode = QrCode.create(hexEncodedPublicKey, size)
|
||||
qrCodeImageView.setImageBitmap(qrCode)
|
||||
cancelButton.setOnClickListener { onCancel?.invoke() }
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.fragment_scan_qr_code.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.qr.ScanListener
|
||||
import org.thoughtcrime.securesms.qr.ScanningThread
|
||||
|
||||
class ScanQRCodeFragment : Fragment() {
|
||||
private val scanningThread = ScanningThread()
|
||||
private var viewCreated = false
|
||||
var scanListener: ScanListener? = null
|
||||
set(value) { field = value; scanningThread.setScanListener(scanListener) }
|
||||
var mode: Mode = Mode.NewConversation
|
||||
set(value) { field = value; updateDescription(); }
|
||||
|
||||
// region Types
|
||||
enum class Mode { NewConversation, LinkDevice }
|
||||
// endregion
|
||||
|
||||
override fun onCreateView(layoutInflater: LayoutInflater, viewGroup: ViewGroup?, bundle: Bundle?): View? {
|
||||
return layoutInflater.inflate(R.layout.fragment_scan_qr_code, viewGroup, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, bundle: Bundle?) {
|
||||
super.onViewCreated(view, bundle)
|
||||
viewCreated = true
|
||||
when (resources.configuration.orientation) {
|
||||
Configuration.ORIENTATION_LANDSCAPE -> overlayView.orientation = LinearLayout.HORIZONTAL
|
||||
else -> overlayView.orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
updateDescription()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
this.scanningThread.setScanListener(scanListener)
|
||||
this.cameraView.onResume()
|
||||
this.cameraView.setPreviewCallback(scanningThread)
|
||||
this.scanningThread.start()
|
||||
if (activity is AppCompatActivity) {
|
||||
val activity = activity as AppCompatActivity
|
||||
activity.supportActionBar?.setTitle(R.string.fragment_scan_qr_code_title)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
this.cameraView.onPause()
|
||||
this.scanningThread.stopScanning()
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfiguration: Configuration) {
|
||||
super.onConfigurationChanged(newConfiguration)
|
||||
this.cameraView.onPause()
|
||||
when (newConfiguration.orientation) {
|
||||
Configuration.ORIENTATION_LANDSCAPE -> overlayView.orientation = LinearLayout.HORIZONTAL
|
||||
else -> overlayView.orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
cameraView.onResume()
|
||||
cameraView.setPreviewCallback(scanningThread)
|
||||
}
|
||||
|
||||
fun updateDescription() {
|
||||
if (!viewCreated) { return }
|
||||
val text = when (mode) {
|
||||
Mode.NewConversation -> R.string.fragment_scan_qr_code_explanation_new_conversation
|
||||
Mode.LinkDevice -> R.string.fragment_scan_qr_code_explanation_link_device
|
||||
}
|
||||
descriptionTextView.setText(text)
|
||||
}
|
||||
}
|
@ -1,273 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.Manifest
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.FragmentManager
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_seed.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
import org.thoughtcrime.securesms.ConversationListActivity
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||
import org.thoughtcrime.securesms.database.Address
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase
|
||||
import org.thoughtcrime.securesms.logging.Log
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.qr.ScanListener
|
||||
import org.thoughtcrime.securesms.util.Hex
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.curve25519.Curve25519
|
||||
import org.whispersystems.libsignal.util.KeyHelper
|
||||
import org.whispersystems.signalservice.loki.api.PairingAuthorisation
|
||||
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec
|
||||
import org.whispersystems.signalservice.loki.utilities.Analytics
|
||||
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
|
||||
import org.whispersystems.signalservice.loki.utilities.hexEncodedPublicKey
|
||||
import org.whispersystems.signalservice.loki.utilities.retryIfNeeded
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
class SeedActivity : BaseActionBarActivity(), DeviceLinkingDelegate, ScanListener {
|
||||
private lateinit var languageFileDirectory: File
|
||||
private var mode = Mode.Register
|
||||
set(newValue) { field = newValue; updateUI() }
|
||||
private var seed: ByteArray? = null
|
||||
set(newValue) { field = newValue; updateMnemonic() }
|
||||
private var mnemonic: String? = null
|
||||
set(newValue) { field = newValue; updateMnemonicTextView() }
|
||||
|
||||
// region Types
|
||||
enum class Mode { Register, Restore, Link }
|
||||
// endregion
|
||||
|
||||
// region Lifecycle
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_seed)
|
||||
setUpLanguageFileDirectory()
|
||||
mnemonicEditText.input.imeOptions = mnemonicEditText.input.imeOptions or 16777216 // Always use incognito keyboard for this
|
||||
updateSeed()
|
||||
copyButton.setOnClickListener { copy() }
|
||||
toggleRegisterModeButton.setOnClickListener { mode = Mode.Register }
|
||||
toggleRestoreModeButton.setOnClickListener { mode = Mode.Restore }
|
||||
toggleLinkModeButton.setOnClickListener { mode = Mode.Link }
|
||||
mainButton.setOnClickListener { handleMainButtonTapped() }
|
||||
scanQRButton.setOnClickListener {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.ifNecessary()
|
||||
.withPermanentDenialDialog(getString(R.string.fragment_scan_qr_code_camera_permission_dialog_message))
|
||||
.onAllGranted {
|
||||
val fragment = ScanQRCodeFragment()
|
||||
fragment.mode = ScanQRCodeFragment.Mode.LinkDevice
|
||||
fragment.scanListener = this
|
||||
supportFragmentManager.beginTransaction().replace(android.R.id.content, fragment).addToBackStack("QR").commitAllowingStateLoss()
|
||||
publicKeyEditText.clearFocus()
|
||||
val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.hideSoftInputFromWindow(publicKeyEditText.windowToken, 0)
|
||||
}
|
||||
.onAnyDenied { Toast.makeText(this, R.string.fragment_scan_qr_code_camera_permission_dialog_message, Toast.LENGTH_SHORT).show() }
|
||||
.execute()
|
||||
}
|
||||
Analytics.shared.track("Seed Screen Viewed")
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region General
|
||||
private fun setUpLanguageFileDirectory() {
|
||||
val languages = listOf( "english", "japanese", "portuguese", "spanish" )
|
||||
val directory = File(applicationInfo.dataDir)
|
||||
for (language in languages) {
|
||||
val fileName = "$language.txt"
|
||||
if (directory.list().contains(fileName)) { continue }
|
||||
val inputStream = assets.open("mnemonic/$fileName")
|
||||
val file = File(directory, fileName)
|
||||
val outputStream = FileOutputStream(file)
|
||||
val buffer = ByteArray(1024)
|
||||
while (true) {
|
||||
val count = inputStream.read(buffer)
|
||||
if (count < 0) { break }
|
||||
outputStream.write(buffer, 0, count)
|
||||
}
|
||||
inputStream.close()
|
||||
outputStream.close()
|
||||
}
|
||||
languageFileDirectory = directory
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Updating
|
||||
private fun updateSeed() {
|
||||
val seed = Curve25519.getInstance(Curve25519.BEST).generateSeed(16)
|
||||
try {
|
||||
IdentityKeyUtil.generateIdentityKeyPair(this, seed + seed)
|
||||
} catch (exception: Exception) {
|
||||
return updateSeed()
|
||||
}
|
||||
this.seed = seed
|
||||
}
|
||||
|
||||
private fun updateUI() {
|
||||
val registerModeVisibility = if (mode == Mode.Register) View.VISIBLE else View.GONE
|
||||
val restoreModeVisibility = if (mode == Mode.Restore) View.VISIBLE else View.GONE
|
||||
val linkModeVisibility = if (mode == Mode.Link) View.VISIBLE else View.GONE
|
||||
seedExplanationTextView1.visibility = registerModeVisibility
|
||||
mnemonicTextView.visibility = registerModeVisibility
|
||||
copyButton.visibility = registerModeVisibility
|
||||
seedExplanationTextView2.visibility = restoreModeVisibility
|
||||
mnemonicEditText.visibility = restoreModeVisibility
|
||||
linkExplanationTextView.visibility = linkModeVisibility
|
||||
publicKeyEditText.visibility = linkModeVisibility
|
||||
scanQRButton.visibility = linkModeVisibility
|
||||
toggleRegisterModeButton.visibility = if (mode != Mode.Register) View.VISIBLE else View.GONE
|
||||
toggleRestoreModeButton.visibility = if (mode != Mode.Restore) View.VISIBLE else View.GONE
|
||||
toggleLinkModeButton.visibility = if (mode != Mode.Link) View.VISIBLE else View.GONE
|
||||
val mainButtonTitleID = when (mode) {
|
||||
Mode.Register -> R.string.activity_key_pair_main_button_title_1
|
||||
Mode.Restore -> R.string.activity_key_pair_main_button_title_2
|
||||
Mode.Link -> R.string.activity_key_pair_main_button_title_3
|
||||
}
|
||||
mainButton.setText(mainButtonTitleID)
|
||||
if (mode == Mode.Restore) {
|
||||
mnemonicEditText.requestFocus()
|
||||
} else {
|
||||
mnemonicEditText.clearFocus()
|
||||
val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.hideSoftInputFromWindow(mnemonicEditText.windowToken, 0)
|
||||
}
|
||||
if (mode == Mode.Link) {
|
||||
publicKeyEditText.requestFocus()
|
||||
} else {
|
||||
publicKeyEditText.clearFocus()
|
||||
val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.hideSoftInputFromWindow(publicKeyEditText.windowToken, 0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateMnemonic() {
|
||||
val hexEncodedSeed = Hex.toStringCondensed(seed)
|
||||
mnemonic = MnemonicCodec(languageFileDirectory).encode(hexEncodedSeed)
|
||||
}
|
||||
|
||||
private fun updateMnemonicTextView() {
|
||||
mnemonicTextView.text = mnemonic!!
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Interaction
|
||||
private fun copy() {
|
||||
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("Mnemonic", mnemonic)
|
||||
clipboard.primaryClip = clip
|
||||
Toast.makeText(this, R.string.activity_key_pair_mnemonic_copied_message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun handleMainButtonTapped() {
|
||||
var seed: ByteArray
|
||||
when (mode) {
|
||||
Mode.Register -> seed = this.seed!!
|
||||
Mode.Restore -> {
|
||||
val mnemonic = mnemonicEditText.text.toString()
|
||||
try {
|
||||
val hexEncodedSeed = MnemonicCodec(languageFileDirectory).decode(mnemonic)
|
||||
seed = Hex.fromStringCondensed(hexEncodedSeed)
|
||||
} catch (e: Exception) {
|
||||
val message = if (e is MnemonicCodec.DecodingError) e.description else MnemonicCodec.DecodingError.Generic.description
|
||||
return Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
Mode.Link -> {
|
||||
val hexEncodedPublicKey = publicKeyEditText.text.trim().toString()
|
||||
if (!PublicKeyValidation.isValid(hexEncodedPublicKey)) {
|
||||
return Toast.makeText(this, "Invalid public key", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
seed = this.seed!!
|
||||
}
|
||||
}
|
||||
val hexEncodedSeed = Hex.toStringCondensed(seed)
|
||||
IdentityKeyUtil.save(this, IdentityKeyUtil.lokiSeedKey, hexEncodedSeed)
|
||||
if (seed.count() == 16) seed += seed
|
||||
if (mode == Mode.Restore) {
|
||||
IdentityKeyUtil.generateIdentityKeyPair(this, seed)
|
||||
}
|
||||
val keyPair = IdentityKeyUtil.getIdentityKeyPair(this)
|
||||
val userHexEncodedPublicKey = keyPair.hexEncodedPublicKey
|
||||
val registrationID = KeyHelper.generateRegistrationId(false)
|
||||
TextSecurePreferences.setLocalRegistrationId(this, registrationID)
|
||||
DatabaseFactory.getIdentityDatabase(this).saveIdentity(Address.fromSerialized(userHexEncodedPublicKey), keyPair.publicKey,
|
||||
IdentityDatabase.VerifiedStatus.VERIFIED, true, System.currentTimeMillis(), true)
|
||||
TextSecurePreferences.setLocalNumber(this, userHexEncodedPublicKey)
|
||||
if (mode == Mode.Restore) {
|
||||
TextSecurePreferences.setRestorationTime(this, System.currentTimeMillis())
|
||||
}
|
||||
when (mode) {
|
||||
Mode.Register -> Analytics.shared.track("Seed Created")
|
||||
Mode.Restore -> Analytics.shared.track("Seed Restored")
|
||||
Mode.Link -> Analytics.shared.track("Device Linking Attempted")
|
||||
}
|
||||
if (mode == Mode.Link) {
|
||||
TextSecurePreferences.setHasSeenWelcomeScreen(this, true)
|
||||
TextSecurePreferences.setPromptedPushRegistration(this, true)
|
||||
val masterHexEncodedPublicKey = publicKeyEditText.text.trim().toString()
|
||||
val authorisation = PairingAuthorisation(masterHexEncodedPublicKey, userHexEncodedPublicKey).sign(PairingAuthorisation.Type.REQUEST, keyPair.privateKey.serialize())
|
||||
if (authorisation == null) {
|
||||
Log.d("Loki", "Failed to sign pairing request.")
|
||||
resetForRegistration()
|
||||
return Toast.makeText(application, "Couldn't start device linking process.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
val application = ApplicationContext.getInstance(this)
|
||||
application.startLongPollingIfNeeded()
|
||||
application.setUpP2PAPI()
|
||||
application.setUpStorageAPIIfNeeded()
|
||||
DeviceLinkingDialog.show(this, DeviceLinkingView.Mode.Slave, this)
|
||||
AsyncTask.execute {
|
||||
retryIfNeeded(8) {
|
||||
sendPairingAuthorisationMessage(this@SeedActivity, authorisation.primaryDevicePublicKey, authorisation)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
startActivity(Intent(this, DisplayNameActivity::class.java))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) {
|
||||
Analytics.shared.track("Device Linked Successfully")
|
||||
if (pairingAuthorisation.secondaryDevicePublicKey == TextSecurePreferences.getLocalNumber(this)) {
|
||||
TextSecurePreferences.setMasterHexEncodedPublicKey(this, pairingAuthorisation.primaryDevicePublicKey)
|
||||
}
|
||||
startActivity(Intent(this, ConversationListActivity::class.java))
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun handleDeviceLinkingDialogDismissed() {
|
||||
resetForRegistration()
|
||||
}
|
||||
|
||||
private fun resetForRegistration() {
|
||||
IdentityKeyUtil.delete(this, IdentityKeyUtil.lokiSeedKey)
|
||||
TextSecurePreferences.removeLocalNumber(this)
|
||||
TextSecurePreferences.setHasSeenWelcomeScreen(this, false)
|
||||
TextSecurePreferences.setPromptedPushRegistration(this, false)
|
||||
}
|
||||
|
||||
override fun onQrDataFound(data: String?) {
|
||||
runOnUiThread {
|
||||
if (data != null && PublicKeyValidation.isValid(data.trim())) {
|
||||
publicKeyEditText.setText(data.trim())
|
||||
supportFragmentManager.popBackStackImmediate("QR", FragmentManager.POP_BACK_STACK_INCLUSIVE)
|
||||
handleMainButtonTapped()
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
}
|
@ -3,7 +3,7 @@ package org.thoughtcrime.securesms.loki.redesign.activities
|
||||
import android.content.Context
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.devicelist.Device
|
||||
import org.thoughtcrime.securesms.loki.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.util.AsyncLoader
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.loki.api.LokiStorageAPI
|
||||
|
@ -12,7 +12,7 @@ import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.dialog_link_device_master_mode.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.loki.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.QRCodeUtilities
|
||||
import org.thoughtcrime.securesms.loki.toPx
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
|
@ -12,7 +12,7 @@ import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.dialog_link_device_slave_mode.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.loki.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLinkingSession
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
package org.thoughtcrime.securesms.loki.redesign.messaging
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
@ -1,4 +1,4 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
package org.thoughtcrime.securesms.loki.redesign.messaging
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
@ -1,4 +1,4 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
package org.thoughtcrime.securesms.loki.redesign.messaging
|
||||
|
||||
import android.content.Context
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
@ -1,4 +1,4 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
package org.thoughtcrime.securesms.loki.redesign.messaging
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
@ -1,4 +1,4 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
package org.thoughtcrime.securesms.loki.redesign.utilities
|
||||
|
||||
import android.content.ContentValues
|
||||
import net.sqlcipher.Cursor
|
@ -1,4 +1,4 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
package org.thoughtcrime.securesms.loki.redesign.utilities
|
||||
|
||||
import android.content.Context
|
||||
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec
|
@ -9,7 +9,7 @@ import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.view_conversation.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||
import org.thoughtcrime.securesms.loki.LokiAPIUtilities.populateUserHexEncodedPublicKeyCacheIfNeeded
|
||||
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities.populateUserHexEncodedPublicKeyCacheIfNeeded
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MentionUtilities.highlightMentions
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
import org.thoughtcrime.securesms.util.DateUtils
|
||||
|
@ -20,10 +20,8 @@ import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.loki.MnemonicUtilities;
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
Loading…
Reference in New Issue
Block a user