mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-24 02:25:19 +00:00
feat: add link device implementation and fixes for updating config syncs and forcing config syncs
This commit is contained in:
parent
3a09d23337
commit
ef3e172379
@ -26,29 +26,32 @@ import kotlinx.coroutines.flow.*
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import org.session.libsession.messaging.threads.recipients.RecipientModifiedListener
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import org.greenrobot.eventbus.Subscribe
|
||||||
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
|
import org.session.libsession.utilities.GroupUtil
|
||||||
|
import org.session.libsession.utilities.ProfilePictureModifiedEvent
|
||||||
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
|
import org.session.libsession.utilities.Util
|
||||||
|
import org.session.libsignal.service.loki.utilities.mentions.MentionsManager
|
||||||
|
import org.session.libsignal.service.loki.utilities.toHexString
|
||||||
|
import org.session.libsignal.utilities.ThreadUtils
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationActivity
|
import org.thoughtcrime.securesms.conversation.ConversationActivity
|
||||||
import org.session.libsession.utilities.GroupUtil
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||||
|
import org.thoughtcrime.securesms.loki.dialogs.*
|
||||||
|
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocolV2
|
||||||
import org.thoughtcrime.securesms.loki.utilities.*
|
import org.thoughtcrime.securesms.loki.utilities.*
|
||||||
import org.thoughtcrime.securesms.loki.views.ConversationView
|
import org.thoughtcrime.securesms.loki.views.ConversationView
|
||||||
import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetViewDelegate
|
import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetViewDelegate
|
||||||
import org.thoughtcrime.securesms.loki.views.SeedReminderViewDelegate
|
import org.thoughtcrime.securesms.loki.views.SeedReminderViewDelegate
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp
|
import org.thoughtcrime.securesms.mms.GlideApp
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
|
||||||
import org.session.libsession.utilities.Util
|
|
||||||
import org.session.libsignal.service.loki.utilities.mentions.MentionsManager
|
|
||||||
import org.session.libsignal.utilities.ThreadUtils
|
|
||||||
import org.session.libsignal.service.loki.utilities.toHexString
|
|
||||||
import org.thoughtcrime.securesms.loki.dialogs.*
|
|
||||||
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocolV2
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
class HomeActivity : PassphraseRequiredActionBarActivity,
|
class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||||
ConversationClickListener,
|
ConversationClickListener,
|
||||||
SeedReminderViewDelegate,
|
SeedReminderViewDelegate,
|
||||||
NewConversationButtonSetViewDelegate {
|
NewConversationButtonSetViewDelegate {
|
||||||
@ -62,8 +65,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// region Lifecycle
|
// region Lifecycle
|
||||||
constructor() : super()
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
||||||
super.onCreate(savedInstanceState, isReady)
|
super.onCreate(savedInstanceState, isReady)
|
||||||
// Double check that the long poller is up
|
// Double check that the long poller is up
|
||||||
@ -152,17 +153,19 @@ class HomeActivity : PassphraseRequiredActionBarActivity,
|
|||||||
}
|
}
|
||||||
this.broadcastReceiver = broadcastReceiver
|
this.broadcastReceiver = broadcastReceiver
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter("blockedContactsChanged"))
|
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter("blockedContactsChanged"))
|
||||||
lifecycleScope.launchWhenResumed {
|
lifecycleScope.launch {
|
||||||
// update things based on TextSecurePrefs (profile info etc)
|
// update things based on TextSecurePrefs (profile info etc)
|
||||||
TextSecurePreferences.events.filter { it == TextSecurePreferences.PROFILE_NAME_PREF }.collect {
|
TextSecurePreferences.events.filter { it == TextSecurePreferences.PROFILE_NAME_PREF }.collect {
|
||||||
updateProfileButton()
|
updateProfileButton()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EventBus.getDefault().register(this@HomeActivity)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
if (TextSecurePreferences.getLocalNumber(this) == null) { return; } // This can be the case after a secondary device is auto-cleared
|
if (TextSecurePreferences.getLocalNumber(this) == null) {
|
||||||
|
return; } // This can be the case after a secondary device is auto-cleared
|
||||||
profileButton.recycle() // clear cached image before update tje profilePictureView
|
profileButton.recycle() // clear cached image before update tje profilePictureView
|
||||||
profileButton.update()
|
profileButton.update()
|
||||||
val hasViewedSeed = TextSecurePreferences.getHasViewedSeed(this)
|
val hasViewedSeed = TextSecurePreferences.getHasViewedSeed(this)
|
||||||
@ -174,13 +177,17 @@ class HomeActivity : PassphraseRequiredActionBarActivity,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun showKeyPairMigrationSheetIfNeeded() {
|
private fun showKeyPairMigrationSheetIfNeeded() {
|
||||||
if (KeyPairUtilities.hasV2KeyPair(this)) { return }
|
if (KeyPairUtilities.hasV2KeyPair(this)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
val keyPairMigrationSheet = KeyPairMigrationBottomSheet()
|
val keyPairMigrationSheet = KeyPairMigrationBottomSheet()
|
||||||
keyPairMigrationSheet.show(supportFragmentManager, keyPairMigrationSheet.tag)
|
keyPairMigrationSheet.show(supportFragmentManager, keyPairMigrationSheet.tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showKeyPairMigrationSuccessSheetIfNeeded() {
|
private fun showKeyPairMigrationSuccessSheetIfNeeded() {
|
||||||
if (!KeyPairUtilities.hasV2KeyPair(this) || !TextSecurePreferences.getIsMigratingKeyPair(this)) { return }
|
if (!KeyPairUtilities.hasV2KeyPair(this) || !TextSecurePreferences.getIsMigratingKeyPair(this)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
val keyPairMigrationSuccessSheet = KeyPairMigrationSuccessBottomSheet()
|
val keyPairMigrationSuccessSheet = KeyPairMigrationSuccessBottomSheet()
|
||||||
keyPairMigrationSuccessSheet.show(supportFragmentManager, keyPairMigrationSuccessSheet.tag)
|
keyPairMigrationSuccessSheet.show(supportFragmentManager, keyPairMigrationSuccessSheet.tag)
|
||||||
TextSecurePreferences.setIsMigratingKeyPair(this, false)
|
TextSecurePreferences.setIsMigratingKeyPair(this, false)
|
||||||
@ -199,6 +206,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity,
|
|||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver)
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver)
|
||||||
}
|
}
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
EventBus.getDefault().unregister(this)
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
@ -208,6 +216,13 @@ class HomeActivity : PassphraseRequiredActionBarActivity,
|
|||||||
emptyStateContainer.visibility = if (threadCount == 0) View.VISIBLE else View.GONE
|
emptyStateContainer.visibility = if (threadCount == 0) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
|
fun onUpdateProfileEvent(event: ProfilePictureModifiedEvent) {
|
||||||
|
if (event.recipient.isLocalNumber) {
|
||||||
|
updateProfileButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateProfileButton() {
|
private fun updateProfileButton() {
|
||||||
profileButton.publicKey = publicKey
|
profileButton.publicKey = publicKey
|
||||||
profileButton.displayName = TextSecurePreferences.getProfileName(this)
|
profileButton.displayName = TextSecurePreferences.getProfileName(this)
|
||||||
@ -307,7 +322,8 @@ class HomeActivity : PassphraseRequiredActionBarActivity,
|
|||||||
}
|
}
|
||||||
val dialog = AlertDialog.Builder(this)
|
val dialog = AlertDialog.Builder(this)
|
||||||
dialog.setMessage(dialogMessage)
|
dialog.setMessage(dialogMessage)
|
||||||
dialog.setPositiveButton(R.string.yes) { _, _ -> lifecycleScope.launch(Dispatchers.Main) {
|
dialog.setPositiveButton(R.string.yes) { _, _ ->
|
||||||
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
val context = this@HomeActivity as Context
|
val context = this@HomeActivity as Context
|
||||||
|
|
||||||
// Send a leave group message if this is an active closed group
|
// Send a leave group message if this is an active closed group
|
||||||
@ -352,7 +368,8 @@ class HomeActivity : PassphraseRequiredActionBarActivity,
|
|||||||
// Notify the user
|
// Notify the user
|
||||||
val toastMessage = if (recipient.isGroupRecipient) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message
|
val toastMessage = if (recipient.isGroupRecipient) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message
|
||||||
Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show()
|
Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show()
|
||||||
}}
|
}
|
||||||
|
}
|
||||||
dialog.setNegativeButton(R.string.no) { _, _ ->
|
dialog.setNegativeButton(R.string.no) { _, _ ->
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,48 @@
|
|||||||
package org.thoughtcrime.securesms.loki.activities
|
package org.thoughtcrime.securesms.loki.activities
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.FragmentPagerAdapter
|
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentPagerAdapter
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.android.synthetic.main.activity_create_private_chat.*
|
import kotlinx.android.synthetic.main.activity_create_private_chat.*
|
||||||
|
import kotlinx.android.synthetic.main.activity_create_private_chat.tabLayout
|
||||||
|
import kotlinx.android.synthetic.main.activity_create_private_chat.viewPager
|
||||||
|
import kotlinx.android.synthetic.main.activity_link_device.*
|
||||||
import kotlinx.android.synthetic.main.activity_settings.*
|
import kotlinx.android.synthetic.main.activity_settings.*
|
||||||
|
import kotlinx.android.synthetic.main.activity_settings.loader
|
||||||
import kotlinx.android.synthetic.main.fragment_recovery_phrase.*
|
import kotlinx.android.synthetic.main.fragment_recovery_phrase.*
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
|
import org.session.libsignal.libsignal.util.KeyHelper
|
||||||
import org.session.libsignal.service.loki.crypto.MnemonicCodec
|
import org.session.libsignal.service.loki.crypto.MnemonicCodec
|
||||||
|
import org.session.libsignal.service.loki.utilities.hexEncodedPublicKey
|
||||||
import org.session.libsignal.utilities.Hex
|
import org.session.libsignal.utilities.Hex
|
||||||
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||||
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragment
|
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragment
|
||||||
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragmentDelegate
|
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragmentDelegate
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.KeyPairUtilities
|
||||||
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
|
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.push
|
||||||
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo
|
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo
|
||||||
|
|
||||||
class LinkDeviceActivity : BaseActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
|
class LinkDeviceActivity : BaseActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
|
||||||
private val adapter = LinkDeviceActivityAdapter(this)
|
private val adapter = LinkDeviceActivityAdapter(this)
|
||||||
|
private var restoreJob: Job? = null
|
||||||
|
|
||||||
// region Lifecycle
|
// region Lifecycle
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -59,8 +78,45 @@ class LinkDeviceActivity : BaseActionBarActivity(), ScanQRCodeWrapperFragmentDel
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun continueWithSeed(seed: ByteArray) {
|
private fun continueWithSeed(seed: ByteArray) {
|
||||||
|
restoreJob?.cancel()
|
||||||
|
restoreJob = lifecycleScope.launch {
|
||||||
|
// RestoreActivity handles seed this way
|
||||||
|
val keyPairGenerationResult = KeyPairUtilities.generate(seed)
|
||||||
|
val x25519KeyPair = keyPairGenerationResult.x25519KeyPair
|
||||||
|
KeyPairUtilities.store(this@LinkDeviceActivity, seed, keyPairGenerationResult.ed25519KeyPair, x25519KeyPair)
|
||||||
|
val userHexEncodedPublicKey = x25519KeyPair.hexEncodedPublicKey
|
||||||
|
val registrationID = KeyHelper.generateRegistrationId(false)
|
||||||
|
TextSecurePreferences.setLocalRegistrationId(this@LinkDeviceActivity, registrationID)
|
||||||
|
TextSecurePreferences.setLocalNumber(this@LinkDeviceActivity, userHexEncodedPublicKey)
|
||||||
|
TextSecurePreferences.setRestorationTime(this@LinkDeviceActivity, System.currentTimeMillis())
|
||||||
|
TextSecurePreferences.setHasViewedSeed(this@LinkDeviceActivity, true)
|
||||||
|
|
||||||
loader.isVisible = true
|
loader.isVisible = true
|
||||||
// TODO: Implement
|
val snackBar = Snackbar.make(containerLayout, R.string.activity_link_device_skip_prompt,Snackbar.LENGTH_INDEFINITE)
|
||||||
|
.setAction(R.string.registration_activity__skip) { register() }
|
||||||
|
|
||||||
|
val skipJob = launch {
|
||||||
|
delay(30_000L)
|
||||||
|
snackBar.show()
|
||||||
|
// show a dialog or something saying do you want to skip this bit?
|
||||||
|
}
|
||||||
|
// start polling and wait for updated message
|
||||||
|
ApplicationContext.getInstance(this@LinkDeviceActivity).startPollingIfNeeded()
|
||||||
|
TextSecurePreferences.events.filter { it == TextSecurePreferences.CONFIGURATION_SYNCED }.collect {
|
||||||
|
// handle we've synced
|
||||||
|
snackBar.dismiss()
|
||||||
|
skipJob.cancel()
|
||||||
|
register()
|
||||||
|
}
|
||||||
|
|
||||||
|
loader.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun register() {
|
||||||
|
restoreJob?.cancel()
|
||||||
|
val intent = Intent(this@LinkDeviceActivity, PNModeActivity::class.java)
|
||||||
|
push(intent)
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
}
|
}
|
||||||
@ -86,7 +142,7 @@ private class LinkDeviceActivityAdapter(private val activity: LinkDeviceActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPageTitle(index: Int): CharSequence? {
|
override fun getPageTitle(index: Int): CharSequence {
|
||||||
return when (index) {
|
return when (index) {
|
||||||
0 -> "Recovery Phrase"
|
0 -> "Recovery Phrase"
|
||||||
1 -> "Scan QR Code"
|
1 -> "Scan QR Code"
|
||||||
|
@ -27,29 +27,29 @@ import nl.komponents.kovenant.deferred
|
|||||||
import nl.komponents.kovenant.functional.bind
|
import nl.komponents.kovenant.functional.bind
|
||||||
import nl.komponents.kovenant.task
|
import nl.komponents.kovenant.task
|
||||||
import nl.komponents.kovenant.ui.alwaysUi
|
import nl.komponents.kovenant.ui.alwaysUi
|
||||||
|
import org.session.libsession.messaging.avatars.AvatarHelper
|
||||||
|
import org.session.libsession.messaging.threads.Address
|
||||||
|
import org.session.libsession.utilities.SSKEnvironment.ProfileManagerProtocol
|
||||||
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
|
import org.session.libsession.utilities.preferences.ProfileKeyUtil
|
||||||
|
import org.session.libsignal.service.api.util.StreamDetails
|
||||||
|
import org.session.libsignal.service.loki.api.fileserver.FileServerAPI
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
import org.thoughtcrime.securesms.avatar.AvatarSelection
|
import org.thoughtcrime.securesms.avatar.AvatarSelection
|
||||||
import org.session.libsession.utilities.preferences.ProfileKeyUtil
|
|
||||||
import org.session.libsession.messaging.threads.Address
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
import org.thoughtcrime.securesms.loki.dialogs.ChangeUiModeDialog
|
import org.thoughtcrime.securesms.loki.dialogs.ChangeUiModeDialog
|
||||||
import org.thoughtcrime.securesms.loki.dialogs.ClearAllDataDialog
|
import org.thoughtcrime.securesms.loki.dialogs.ClearAllDataDialog
|
||||||
import org.thoughtcrime.securesms.loki.dialogs.SeedDialog
|
import org.thoughtcrime.securesms.loki.dialogs.SeedDialog
|
||||||
|
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol
|
||||||
import org.thoughtcrime.securesms.loki.utilities.UiModeUtilities
|
import org.thoughtcrime.securesms.loki.utilities.UiModeUtilities
|
||||||
import org.thoughtcrime.securesms.loki.utilities.push
|
import org.thoughtcrime.securesms.loki.utilities.push
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp
|
import org.thoughtcrime.securesms.mms.GlideApp
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions
|
import org.thoughtcrime.securesms.permissions.Permissions
|
||||||
import org.session.libsession.messaging.avatars.AvatarHelper
|
|
||||||
import org.session.libsession.utilities.SSKEnvironment.ProfileManagerProtocol
|
|
||||||
import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints
|
import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints
|
||||||
import org.thoughtcrime.securesms.util.BitmapDecodingException
|
import org.thoughtcrime.securesms.util.BitmapDecodingException
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil
|
import org.thoughtcrime.securesms.util.BitmapUtil
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
|
||||||
import org.session.libsignal.service.api.util.StreamDetails
|
|
||||||
import org.session.libsignal.service.loki.api.fileserver.FileServerAPI
|
|
||||||
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol
|
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
@ -207,6 +207,12 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
// updating the profile name or picture
|
// updating the profile name or picture
|
||||||
if (profilePicture != null || displayName != null) {
|
if (profilePicture != null || displayName != null) {
|
||||||
task {
|
task {
|
||||||
|
if (isUpdatingProfilePicture && profilePicture != null) {
|
||||||
|
AvatarHelper.setAvatar(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)!!), profilePicture)
|
||||||
|
TextSecurePreferences.setProfileAvatarId(this, SecureRandom().nextInt())
|
||||||
|
ProfileKeyUtil.setEncodedProfileKey(this, encodedProfileKey)
|
||||||
|
ApplicationContext.getInstance(this).updateOpenGroupProfilePicturesIfNeeded()
|
||||||
|
}
|
||||||
MultiDeviceProtocol.forceSyncConfigurationNowIfNeeded(this@SettingsActivity)
|
MultiDeviceProtocol.forceSyncConfigurationNowIfNeeded(this@SettingsActivity)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -216,15 +222,11 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
if (displayName != null) {
|
if (displayName != null) {
|
||||||
btnGroupNameDisplay.text = displayName
|
btnGroupNameDisplay.text = displayName
|
||||||
}
|
}
|
||||||
displayNameToBeUploaded = null
|
|
||||||
if (isUpdatingProfilePicture && profilePicture != null) {
|
if (isUpdatingProfilePicture && profilePicture != null) {
|
||||||
AvatarHelper.setAvatar(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)!!), profilePicture)
|
|
||||||
TextSecurePreferences.setProfileAvatarId(this, SecureRandom().nextInt())
|
|
||||||
ProfileKeyUtil.setEncodedProfileKey(this, encodedProfileKey)
|
|
||||||
ApplicationContext.getInstance(this).updateOpenGroupProfilePicturesIfNeeded()
|
|
||||||
profilePictureView.recycle() // clear cached image before update tje profilePictureView
|
profilePictureView.recycle() // clear cached image before update tje profilePictureView
|
||||||
profilePictureView.update()
|
profilePictureView.update()
|
||||||
}
|
}
|
||||||
|
displayNameToBeUploaded = null
|
||||||
profilePictureToBeUploaded = null
|
profilePictureToBeUploaded = null
|
||||||
loader.isVisible = false
|
loader.isVisible = false
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
|||||||
import org.session.libsession.messaging.threads.Address
|
import org.session.libsession.messaging.threads.Address
|
||||||
import org.session.libsession.messaging.threads.recipients.Recipient
|
import org.session.libsession.messaging.threads.recipients.Recipient
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
|
import org.session.libsession.utilities.preferences.ProfileKeyUtil
|
||||||
import org.session.libsignal.libsignal.util.guava.Optional
|
import org.session.libsignal.libsignal.util.guava.Optional
|
||||||
import org.session.libsignal.service.api.push.SignalServiceAddress
|
import org.session.libsignal.service.api.push.SignalServiceAddress
|
||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
@ -18,12 +19,10 @@ import org.session.libsignal.utilities.logging.Log
|
|||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase
|
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
|
||||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
|
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
|
||||||
import org.thoughtcrime.securesms.loki.utilities.ContactUtilities
|
import org.thoughtcrime.securesms.loki.utilities.ContactUtilities
|
||||||
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities
|
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities
|
||||||
import org.thoughtcrime.securesms.sskenvironment.ProfileManager
|
import java.security.SecureRandom
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object MultiDeviceProtocol {
|
object MultiDeviceProtocol {
|
||||||
@ -82,12 +81,18 @@ object MultiDeviceProtocol {
|
|||||||
// TODO: remove this after we migrate to new message receiving pipeline
|
// TODO: remove this after we migrate to new message receiving pipeline
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun handleConfigurationMessage(context: Context, content: SignalServiceProtos.Content, senderPublicKey: String, timestamp: Long) {
|
fun handleConfigurationMessage(context: Context, content: SignalServiceProtos.Content, senderPublicKey: String, timestamp: Long) {
|
||||||
// if (TextSecurePreferences.getConfigurationMessageSynced(context)) return
|
if (TextSecurePreferences.getConfigurationMessageSynced(context) && !TextSecurePreferences.shouldUpdateProfile(context, timestamp)) return
|
||||||
val configurationMessage = ConfigurationMessage.fromProto(content) ?: return
|
val configurationMessage = ConfigurationMessage.fromProto(content) ?: return
|
||||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context) ?: return
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context) ?: return
|
||||||
if (senderPublicKey != userPublicKey) return
|
if (senderPublicKey != userPublicKey) return
|
||||||
val storage = MessagingConfiguration.shared.storage
|
val storage = MessagingConfiguration.shared.storage
|
||||||
val allClosedGroupPublicKeys = storage.getAllClosedGroupPublicKeys()
|
val allClosedGroupPublicKeys = storage.getAllClosedGroupPublicKeys()
|
||||||
|
|
||||||
|
val threadDatabase = DatabaseFactory.getThreadDatabase(context)
|
||||||
|
val recipientDatabase = DatabaseFactory.getRecipientDatabase(context)
|
||||||
|
|
||||||
|
val ourRecipient = Recipient.from(context, Address.fromSerialized(userPublicKey),false)
|
||||||
|
|
||||||
for (closedGroup in configurationMessage.closedGroups) {
|
for (closedGroup in configurationMessage.closedGroups) {
|
||||||
if (allClosedGroupPublicKeys.contains(closedGroup.publicKey)) continue
|
if (allClosedGroupPublicKeys.contains(closedGroup.publicKey)) continue
|
||||||
|
|
||||||
@ -109,18 +114,20 @@ object MultiDeviceProtocol {
|
|||||||
if (allOpenGroups.contains(openGroup)) continue
|
if (allOpenGroups.contains(openGroup)) continue
|
||||||
OpenGroupUtilities.addGroup(context, openGroup, 1)
|
OpenGroupUtilities.addGroup(context, openGroup, 1)
|
||||||
}
|
}
|
||||||
if (configurationMessage.profileKey.isNotEmpty()) {
|
|
||||||
val profileKey = Base64.encodeBytes(configurationMessage.profileKey)
|
|
||||||
TextSecurePreferences.setProfileKey(context, profileKey)
|
|
||||||
}
|
|
||||||
if (!configurationMessage.profilePicture.isNullOrEmpty()) {
|
|
||||||
TextSecurePreferences.setProfilePictureURL(context, configurationMessage.profilePicture)
|
|
||||||
}
|
|
||||||
if (configurationMessage.displayName.isNotEmpty()) {
|
if (configurationMessage.displayName.isNotEmpty()) {
|
||||||
TextSecurePreferences.setProfileName(context, configurationMessage.displayName)
|
TextSecurePreferences.setProfileName(context, configurationMessage.displayName)
|
||||||
|
recipientDatabase.setProfileName(ourRecipient, configurationMessage.displayName)
|
||||||
|
}
|
||||||
|
if (configurationMessage.profileKey.isNotEmpty()) {
|
||||||
|
val profileKey = Base64.encodeBytes(configurationMessage.profileKey)
|
||||||
|
ProfileKeyUtil.setEncodedProfileKey(context, profileKey)
|
||||||
|
recipientDatabase.setProfileKey(ourRecipient, configurationMessage.profileKey)
|
||||||
|
if (!configurationMessage.profilePicture.isNullOrEmpty()) {
|
||||||
|
TextSecurePreferences.setProfilePictureURL(context, configurationMessage.profilePicture)
|
||||||
|
TextSecurePreferences.setProfileAvatarId(context, SecureRandom().nextInt())
|
||||||
|
ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(ourRecipient, configurationMessage.profilePicture))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val threadDatabase = DatabaseFactory.getThreadDatabase(context)
|
|
||||||
val recipientDatabase = DatabaseFactory.getRecipientDatabase(context)
|
|
||||||
for (contact in configurationMessage.contacts) {
|
for (contact in configurationMessage.contacts) {
|
||||||
val address = Address.fromSerialized(contact.publicKey)
|
val address = Address.fromSerialized(contact.publicKey)
|
||||||
val recipient = Recipient.from(context, address, true)
|
val recipient = Recipient.from(context, address, true)
|
||||||
@ -142,5 +149,6 @@ object MultiDeviceProtocol {
|
|||||||
}
|
}
|
||||||
// TODO: handle new configuration message fields or handle in new pipeline
|
// TODO: handle new configuration message fields or handle in new pipeline
|
||||||
TextSecurePreferences.setConfigurationMessageSynced(context, true)
|
TextSecurePreferences.setConfigurationMessageSynced(context, true)
|
||||||
|
TextSecurePreferences.setLastProfileUpdateTime(context, timestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,12 +12,12 @@ import kotlinx.android.synthetic.main.view_profile_picture.view.*
|
|||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import org.session.libsession.messaging.avatars.ProfileContactPhoto
|
import org.session.libsession.messaging.avatars.ProfileContactPhoto
|
||||||
import org.session.libsession.messaging.threads.Address
|
import org.session.libsession.messaging.threads.Address
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
|
||||||
import org.thoughtcrime.securesms.loki.utilities.AvatarPlaceholderGenerator
|
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
|
||||||
import org.session.libsession.messaging.threads.recipients.Recipient
|
import org.session.libsession.messaging.threads.recipients.Recipient
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.session.libsignal.service.loki.utilities.mentions.MentionsManager
|
import org.session.libsignal.service.loki.utilities.mentions.MentionsManager
|
||||||
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.AvatarPlaceholderGenerator
|
||||||
|
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||||
|
|
||||||
// TODO: Look into a better way of handling different sizes. Maybe an enum (with associated values) encapsulating the different modes?
|
// TODO: Look into a better way of handling different sizes. Maybe an enum (with associated values) encapsulating the different modes?
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ class ProfilePictureView : RelativeLayout {
|
|||||||
if (signalProfilePicture != null && (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "0"
|
if (signalProfilePicture != null && (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "0"
|
||||||
&& (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "") {
|
&& (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "") {
|
||||||
glide.clear(imageView)
|
glide.clear(imageView)
|
||||||
glide.load(signalProfilePicture).diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop().into(imageView)
|
glide.load(signalProfilePicture).diskCacheStrategy(DiskCacheStrategy.AUTOMATIC).circleCrop().into(imageView)
|
||||||
imagesCached.add(publicKey)
|
imagesCached.add(publicKey)
|
||||||
} else {
|
} else {
|
||||||
val sizeInPX = resources.getDimensionPixelSize(sizeResId)
|
val sizeInPX = resources.getDimensionPixelSize(sizeResId)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/containerLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
@ -1881,5 +1881,7 @@
|
|||||||
<string name="activity_backup_restore_select_file">Select a file</string>
|
<string name="activity_backup_restore_select_file">Select a file</string>
|
||||||
<string name="activity_backup_restore_explanation_1">Select a backup file and enter the passphrase it was created with.</string>
|
<string name="activity_backup_restore_explanation_1">Select a backup file and enter the passphrase it was created with.</string>
|
||||||
<string name="activity_backup_restore_passphrase">30-digit passphrase</string>
|
<string name="activity_backup_restore_passphrase">30-digit passphrase</string>
|
||||||
|
<!-- LinkDeviceActivity -->
|
||||||
|
<string name="activity_link_device_skip_prompt">This is taking a while, would you like to skip?</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -2,14 +2,17 @@ package org.session.libsession.messaging.sending_receiving.notifications
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import nl.komponents.kovenant.functional.map
|
import nl.komponents.kovenant.functional.map
|
||||||
import okhttp3.*
|
import okhttp3.MediaType
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.RequestBody
|
||||||
import org.session.libsession.messaging.MessagingConfiguration
|
import org.session.libsession.messaging.MessagingConfiguration
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.session.libsignal.utilities.logging.Log
|
|
||||||
import org.session.libsignal.utilities.JsonUtil
|
|
||||||
import org.session.libsignal.service.loki.api.onionrequests.OnionRequestAPI
|
import org.session.libsignal.service.loki.api.onionrequests.OnionRequestAPI
|
||||||
import org.session.libsignal.service.loki.utilities.retryIfNeeded
|
import org.session.libsignal.service.loki.utilities.retryIfNeeded
|
||||||
|
import org.session.libsignal.utilities.JsonUtil
|
||||||
|
import org.session.libsignal.utilities.logging.Log
|
||||||
|
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
object PushNotificationAPI {
|
object PushNotificationAPI {
|
||||||
val context = MessagingConfiguration.shared.context
|
val context = MessagingConfiguration.shared.context
|
||||||
val server = "https://live.apns.getsession.org"
|
val server = "https://live.apns.getsession.org"
|
||||||
|
@ -107,7 +107,8 @@ object TextSecurePreferences {
|
|||||||
|
|
||||||
// region Multi Device
|
// region Multi Device
|
||||||
private const val LAST_CONFIGURATION_SYNC_TIME = "pref_last_configuration_sync_time"
|
private const val LAST_CONFIGURATION_SYNC_TIME = "pref_last_configuration_sync_time"
|
||||||
private const val CONFIGURATION_SYNCED = "pref_configuration_synced"
|
const val CONFIGURATION_SYNCED = "pref_configuration_synced"
|
||||||
|
private const val LAST_PROFILE_UPDATE_TIME = "pref_last_profile_update_time"
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getLastConfigurationSyncTime(context: Context): Long {
|
fun getLastConfigurationSyncTime(context: Context): Long {
|
||||||
@ -127,6 +128,7 @@ object TextSecurePreferences {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun setConfigurationMessageSynced(context: Context, value: Boolean) {
|
fun setConfigurationMessageSynced(context: Context, value: Boolean) {
|
||||||
setBooleanPreference(context, CONFIGURATION_SYNCED, value)
|
setBooleanPreference(context, CONFIGURATION_SYNCED, value)
|
||||||
|
_events.tryEmit(CONFIGURATION_SYNCED)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@ -753,5 +755,14 @@ object TextSecurePreferences {
|
|||||||
fun setIsMigratingKeyPair(context: Context?, newValue: Boolean) {
|
fun setIsMigratingKeyPair(context: Context?, newValue: Boolean) {
|
||||||
setBooleanPreference(context!!, "is_migrating_key_pair", newValue)
|
setBooleanPreference(context!!, "is_migrating_key_pair", newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun setLastProfileUpdateTime(context: Context, profileUpdateTime: Long) {
|
||||||
|
setLongPreference(context, LAST_PROFILE_UPDATE_TIME, profileUpdateTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun shouldUpdateProfile(context: Context, profileUpdateTime: Long) =
|
||||||
|
profileUpdateTime > getLongPreference(context, LAST_PROFILE_UPDATE_TIME, 0)
|
||||||
// endregion
|
// endregion
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user