diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2528296c0b..b86e28f963 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -160,6 +160,8 @@
android:name="org.thoughtcrime.securesms.loki.redesign.activities.NotificationSettingsActivity" />
+
diff --git a/res/drawable/prominent_dialog_button_background.xml b/res/drawable/prominent_dialog_button_background.xml
index a1d03bb009..de3409d482 100644
--- a/res/drawable/prominent_dialog_button_background.xml
+++ b/res/drawable/prominent_dialog_button_background.xml
@@ -3,9 +3,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
-
+
-
+
\ No newline at end of file
diff --git a/res/layout/activity_linked_devices.xml b/res/layout/activity_linked_devices.xml
new file mode 100644
index 0000000000..c816e18295
--- /dev/null
+++ b/res/layout/activity_linked_devices.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/dialog_link_device_master_mode.xml b/res/layout/dialog_link_device_master_mode.xml
new file mode 100644
index 0000000000..04adef415a
--- /dev/null
+++ b/res/layout/dialog_link_device_master_mode.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/menu/menu_linked_devices.xml b/res/menu/menu_linked_devices.xml
new file mode 100644
index 0000000000..85a1a1a57a
--- /dev/null
+++ b/res/menu/menu_linked_devices.xml
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/LinkedDevicesActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/LinkedDevicesActivity.kt
new file mode 100644
index 0000000000..7b7c56aea2
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/LinkedDevicesActivity.kt
@@ -0,0 +1,63 @@
+package org.thoughtcrime.securesms.loki.redesign.activities
+
+import android.os.AsyncTask
+import android.os.Bundle
+import android.support.v7.widget.LinearLayoutManager
+import android.view.Menu
+import android.view.MenuItem
+import kotlinx.android.synthetic.main.activity_linked_devices.*
+import network.loki.messenger.R
+import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
+import org.thoughtcrime.securesms.loki.redesign.dialogs.LinkDeviceMasterModeDialog
+import org.thoughtcrime.securesms.loki.redesign.dialogs.LinkDeviceMasterModeDialogDelegate
+import org.thoughtcrime.securesms.loki.signAndSendPairingAuthorisationMessage
+import org.thoughtcrime.securesms.util.Util
+import org.whispersystems.signalservice.loki.api.PairingAuthorisation
+
+class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LinkDeviceMasterModeDialogDelegate {
+
+ constructor() : super()
+
+ override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
+ super.onCreate(savedInstanceState, isReady)
+ setContentView(R.layout.activity_linked_devices)
+ supportActionBar!!.title = "Linked Devices"
+// val homeAdapter = LinkedDevicesAdapter(this, cursor)
+// recyclerView.adapter = homeAdapter
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ linkDeviceButton.setOnClickListener { linkDevice() }
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.menu_linked_devices, menu)
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ val id = item.itemId
+ when (id) {
+ R.id.linkDeviceButton -> linkDevice()
+ else -> { /* Do nothing */ }
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
+ private fun linkDevice() {
+ val linkDeviceDialog = LinkDeviceMasterModeDialog()
+ linkDeviceDialog.delegate = this
+ linkDeviceDialog.show(supportFragmentManager, "Link Device Dialog")
+ }
+
+ override fun onDeviceLinkRequestAuthorized(authorization: PairingAuthorisation) {
+ AsyncTask.execute {
+ signAndSendPairingAuthorisationMessage(this, authorization)
+ Util.runOnMain {
+
+ }
+ }
+ }
+
+ override fun onDeviceLinkCanceled() {
+ // Do nothing
+ }
+}
\ No newline at end of file
diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/SettingsActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/SettingsActivity.kt
index 8eac97e993..e26846e074 100644
--- a/src/org/thoughtcrime/securesms/loki/redesign/activities/SettingsActivity.kt
+++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/SettingsActivity.kt
@@ -90,6 +90,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
privacyButton.setOnClickListener { showPrivacySettings() }
notificationsButton.setOnClickListener { showNotificationSettings() }
chatsButton.setOnClickListener { showChatSettings() }
+ linkedDevicesButton.setOnClickListener { showLinkedDevices() }
seedButton.setOnClickListener { showSeed() }
clearAllDataButton.setOnClickListener { clearAllData() }
}
@@ -265,6 +266,11 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
push(intent)
}
+ private fun showLinkedDevices() {
+ val intent = Intent(this, LinkedDevicesActivity::class.java)
+ push(intent)
+ }
+
private fun showSeed() {
SeedDialog().show(supportFragmentManager, "Recovery Phrase Dialog")
}
diff --git a/src/org/thoughtcrime/securesms/loki/redesign/dialogs/LinkDeviceMasterModeDialog.kt b/src/org/thoughtcrime/securesms/loki/redesign/dialogs/LinkDeviceMasterModeDialog.kt
new file mode 100644
index 0000000000..e671de605f
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/loki/redesign/dialogs/LinkDeviceMasterModeDialog.kt
@@ -0,0 +1,87 @@
+package org.thoughtcrime.securesms.loki.redesign.dialogs
+
+import android.app.Dialog
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.os.Bundle
+import android.support.v4.app.DialogFragment
+import android.support.v7.app.AlertDialog
+import android.view.LayoutInflater
+import android.view.View
+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.QRCodeUtilities
+import org.thoughtcrime.securesms.loki.toPx
+import org.thoughtcrime.securesms.util.TextSecurePreferences
+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
+import org.whispersystems.signalservice.loki.crypto.MnemonicCodec
+
+class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListener {
+ private val languageFileDirectory by lazy { MnemonicUtilities.getLanguageFileDirectory(context!!) }
+ private lateinit var contentView: View
+ private var authorization: PairingAuthorisation? = null
+ var delegate: LinkDeviceMasterModeDialogDelegate? = null
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val builder = AlertDialog.Builder(context!!)
+ contentView = LayoutInflater.from(context!!).inflate(R.layout.dialog_link_device_master_mode, null)
+ val size = toPx(128, resources)
+ val hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context!!)
+ val qrCode = QRCodeUtilities.encode(hexEncodedPublicKey, size)
+ contentView.qrCodeImageView.setImageBitmap(qrCode)
+ contentView.cancelButton.setOnClickListener { onDeviceLinkCanceled() }
+ contentView.authorizeButton.setOnClickListener { authorizeDeviceLink() }
+ builder.setView(contentView)
+ DeviceLinkingSession.shared.startListeningForLinkingRequests() // FIXME: This flag is named poorly as it's actually also used for authorizations
+ DeviceLinkingSession.shared.addListener(this)
+ val result = builder.create()
+ result.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+ return result
+ }
+
+ override fun requestUserAuthorization(authorization: PairingAuthorisation) {
+ if (authorization.type != PairingAuthorisation.Type.REQUEST || authorization.primaryDevicePublicKey != TextSecurePreferences.getLocalNumber(context!!) || this.authorization != null) { return }
+ Util.runOnMain {
+ this.authorization = authorization
+ contentView.qrCodeImageView.visibility = View.GONE
+ val titleTextViewLayoutParams = contentView.titleTextView.layoutParams as LinearLayout.LayoutParams
+ titleTextViewLayoutParams.topMargin = toPx(8, resources)
+ contentView.titleTextView.layoutParams = titleTextViewLayoutParams
+ contentView.titleTextView.text = "Linking Request Received"
+ contentView.explanationTextView.text = "Please check that the words below match those shown on your other device"
+ contentView.mnemonicTextView.visibility = View.VISIBLE
+ contentView.mnemonicTextView.text = MnemonicUtilities.getFirst3Words(MnemonicCodec(languageFileDirectory), authorization.secondaryDevicePublicKey)
+ contentView.authorizeButton.visibility = View.VISIBLE
+ }
+ }
+
+ private fun authorizeDeviceLink() {
+ val authorization = this.authorization ?: return
+ delegate?.onDeviceLinkRequestAuthorized(authorization)
+ DeviceLinkingSession.shared.stopListeningForLinkingRequests()
+ DeviceLinkingSession.shared.removeListener(this)
+ dismiss()
+ }
+
+ private fun onDeviceLinkCanceled() {
+ DeviceLinkingSession.shared.stopListeningForLinkingRequests()
+ DeviceLinkingSession.shared.removeListener(this)
+ if (authorization != null) {
+ DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(authorization!!.secondaryDevicePublicKey)
+ }
+ dismiss()
+ delegate?.onDeviceLinkCanceled()
+ }
+}
+
+interface LinkDeviceMasterModeDialogDelegate {
+
+ fun onDeviceLinkRequestAuthorized(authorization: PairingAuthorisation)
+ fun onDeviceLinkCanceled()
+}