Implement linked devices screen redesign
							parent
							
								
									38f3c3cff6
								
							
						
					
					
						commit
						7424684c75
					
				@ -0,0 +1,37 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<RelativeLayout
 | 
			
		||||
    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="match_parent"
 | 
			
		||||
    android:background="@drawable/default_session_background">
 | 
			
		||||
 | 
			
		||||
    <android.support.v7.widget.RecyclerView
 | 
			
		||||
        android:id="@+id/recyclerView"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent" />
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:gravity="center_horizontal"
 | 
			
		||||
        android:orientation="vertical"
 | 
			
		||||
        android:layout_centerInParent="true">
 | 
			
		||||
 | 
			
		||||
        <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:textSize="@dimen/medium_font_size"
 | 
			
		||||
            android:textColor="@color/text"
 | 
			
		||||
            android:text="You don't have any linked devices yet" />
 | 
			
		||||
 | 
			
		||||
        <Button
 | 
			
		||||
            style="@style/MediumProminentOutlineButton"
 | 
			
		||||
            android:id="@+id/linkDeviceButton"
 | 
			
		||||
            android:layout_width="196dp"
 | 
			
		||||
            android:layout_height="@dimen/medium_button_height"
 | 
			
		||||
            android:layout_marginTop="@dimen/medium_spacing"
 | 
			
		||||
            android:text="Link a Device" />
 | 
			
		||||
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
</RelativeLayout>
 | 
			
		||||
@ -0,0 +1,85 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout
 | 
			
		||||
    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="match_parent"
 | 
			
		||||
    android:background="@drawable/default_dialog_background_inset"
 | 
			
		||||
    android:gravity="center_horizontal"
 | 
			
		||||
    android:orientation="vertical"
 | 
			
		||||
    android:paddingLeft="32dp"
 | 
			
		||||
    android:paddingTop="@dimen/medium_spacing"
 | 
			
		||||
    android:paddingRight="32dp"
 | 
			
		||||
    android:paddingBottom="@dimen/medium_spacing">
 | 
			
		||||
 | 
			
		||||
    <RelativeLayout
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_marginTop="@dimen/small_spacing"
 | 
			
		||||
        android:gravity="center">
 | 
			
		||||
 | 
			
		||||
        <ImageView
 | 
			
		||||
            android:id="@+id/qrCodeImageView"
 | 
			
		||||
            android:layout_width="128dp"
 | 
			
		||||
            android:layout_height="128dp" />
 | 
			
		||||
 | 
			
		||||
    </RelativeLayout>
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/titleTextView"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_marginTop="@dimen/large_spacing"
 | 
			
		||||
        android:text="Waiting for Device"
 | 
			
		||||
        android:textColor="@color/text"
 | 
			
		||||
        android:textStyle="bold"
 | 
			
		||||
        android:textSize="@dimen/medium_font_size" />
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/explanationTextView"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_marginTop="@dimen/large_spacing"
 | 
			
		||||
        android:text="Create a new account on your other device and click "Link to an existing account" to start the linking process"
 | 
			
		||||
        android:textColor="@color/text"
 | 
			
		||||
        android:alpha="0.6"
 | 
			
		||||
        android:textSize="@dimen/small_font_size"
 | 
			
		||||
        android:textAlignment="center" />
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/mnemonicTextView"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_marginTop="20dp"
 | 
			
		||||
        android:text="puffin circle idled"
 | 
			
		||||
        android:textColor="@color/text"
 | 
			
		||||
        android:textSize="@dimen/small_font_size"
 | 
			
		||||
        android:textAlignment="center"
 | 
			
		||||
        android:visibility="gone" />
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_marginTop="@dimen/large_spacing"
 | 
			
		||||
        android:orientation="horizontal">
 | 
			
		||||
 | 
			
		||||
        <Button
 | 
			
		||||
            style="@style/UnimportantDialogButton"
 | 
			
		||||
            android:id="@+id/cancelButton"
 | 
			
		||||
            android:layout_width="0dp"
 | 
			
		||||
            android:layout_height="@dimen/small_button_height"
 | 
			
		||||
            android:layout_weight="1"
 | 
			
		||||
            android:text="Cancel" />
 | 
			
		||||
 | 
			
		||||
        <Button
 | 
			
		||||
            style="@style/ProminentDialogButton"
 | 
			
		||||
            android:id="@+id/authorizeButton"
 | 
			
		||||
            android:layout_width="0dp"
 | 
			
		||||
            android:layout_height="@dimen/small_button_height"
 | 
			
		||||
            android:layout_weight="1"
 | 
			
		||||
            android:layout_marginLeft="@dimen/medium_spacing"
 | 
			
		||||
            android:text="Authorize"
 | 
			
		||||
            android:visibility="gone" />
 | 
			
		||||
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
@ -0,0 +1,12 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<menu
 | 
			
		||||
    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto">
 | 
			
		||||
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/linkDeviceButton"
 | 
			
		||||
        android:title="Link Device"
 | 
			
		||||
        android:icon="@drawable/ic_plus_24"
 | 
			
		||||
        app:showAsAction="always" />
 | 
			
		||||
 | 
			
		||||
</menu>
 | 
			
		||||
@ -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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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()
 | 
			
		||||
}
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue