123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- /*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * @author Andy Scherzinger
- * @author Marcel Hibbe
- * @author Ezhil Shanmugham
- * Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
- * Copyright (C) 2021 Andy Scherzinger (infoi@andy-scherzinger.de)
- * Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
- * Copyright (C) 2023 Ezhil Shanmugham <ezhil56x.contact@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package com.nextcloud.talk.activities
- import android.app.KeyguardManager
- import android.content.Context
- import android.content.Intent
- import android.os.Bundle
- import android.provider.ContactsContract
- import android.text.TextUtils
- import android.util.Log
- import androidx.activity.OnBackPressedCallback
- import androidx.lifecycle.DefaultLifecycleObserver
- import androidx.lifecycle.LifecycleOwner
- import androidx.lifecycle.ProcessLifecycleOwner
- import autodagger.AutoInjector
- import com.bluelinelabs.conductor.Conductor
- import com.bluelinelabs.conductor.Router
- import com.bluelinelabs.conductor.RouterTransaction
- import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
- import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
- import com.google.android.material.snackbar.Snackbar
- import com.nextcloud.talk.BuildConfig
- import com.nextcloud.talk.R
- import com.nextcloud.talk.api.NcApi
- import com.nextcloud.talk.application.NextcloudTalkApplication
- import com.nextcloud.talk.chat.ChatActivity
- import com.nextcloud.talk.controllers.ServerSelectionController
- import com.nextcloud.talk.controllers.WebViewLoginController
- import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
- import com.nextcloud.talk.conversationlist.ConversationsListActivity
- import com.nextcloud.talk.data.user.model.User
- import com.nextcloud.talk.databinding.ActivityMainBinding
- import com.nextcloud.talk.lock.LockedActivity
- import com.nextcloud.talk.models.json.conversations.RoomOverall
- import com.nextcloud.talk.users.UserManager
- import com.nextcloud.talk.utils.ApiUtils
- import com.nextcloud.talk.utils.SecurityUtils
- import com.nextcloud.talk.utils.bundle.BundleKeys
- import com.nextcloud.talk.utils.bundle.BundleKeys.ADD_ACCOUNT
- import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ACTIVE_CONVERSATION
- import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID
- import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
- import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY
- import io.reactivex.Observer
- import io.reactivex.SingleObserver
- import io.reactivex.android.schedulers.AndroidSchedulers
- import io.reactivex.disposables.Disposable
- import io.reactivex.schedulers.Schedulers
- import org.parceler.Parcels
- import javax.inject.Inject
- @AutoInjector(NextcloudTalkApplication::class)
- class MainActivity : BaseActivity(), ActionBarProvider {
- lateinit var binding: ActivityMainBinding
- @Inject
- lateinit var ncApi: NcApi
- @Inject
- lateinit var userManager: UserManager
- private var router: Router? = null
- private val onBackPressedCallback = object : OnBackPressedCallback(true) {
- override fun handleOnBackPressed() {
- if (!router!!.handleBack()) {
- finish()
- }
- }
- }
- @Suppress("Detekt.TooGenericExceptionCaught")
- override fun onCreate(savedInstanceState: Bundle?) {
- Log.d(TAG, "onCreate: Activity: " + System.identityHashCode(this).toString())
- super.onCreate(savedInstanceState)
- ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
- override fun onStart(owner: LifecycleOwner) {
- lockScreenIfConditionsApply()
- }
- })
- // Set the default theme to replace the launch screen theme.
- setTheme(R.style.AppTheme)
- binding = ActivityMainBinding.inflate(layoutInflater)
- setContentView(binding.root)
- NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
- setSupportActionBar(binding.toolbar)
- router = Conductor.attachRouter(this, binding.controllerContainer, savedInstanceState)
- if (intent.hasExtra(ADD_ACCOUNT) && intent.getBooleanExtra(ADD_ACCOUNT, false)) {
- addAccount()
- } else if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
- onNewIntent(intent)
- } else if (!router!!.hasRootController()) {
- if (!appPreferences.isDbRoomMigrated) {
- appPreferences.isDbRoomMigrated = true
- }
- userManager.users.subscribe(object : SingleObserver<List<User>> {
- override fun onSubscribe(d: Disposable) {
- // unused atm
- }
- override fun onSuccess(users: List<User>) {
- if (users.isNotEmpty()) {
- runOnUiThread {
- openConversationList()
- }
- } else {
- runOnUiThread {
- launchLoginScreen()
- }
- }
- }
- override fun onError(e: Throwable) {
- Log.e(TAG, "Error loading existing users", e)
- }
- })
- }
- onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
- }
- fun lockScreenIfConditionsApply() {
- val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
- if (keyguardManager.isKeyguardSecure && appPreferences.isScreenLocked) {
- if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)) {
- val lockIntent = Intent(context, LockedActivity::class.java)
- startActivity(lockIntent)
- }
- }
- }
- private fun launchLoginScreen() {
- if (!TextUtils.isEmpty(resources.getString(R.string.weblogin_url))) {
- router!!.pushController(
- RouterTransaction.with(
- WebViewLoginController(resources.getString(R.string.weblogin_url), false)
- )
- .pushChangeHandler(HorizontalChangeHandler())
- .popChangeHandler(HorizontalChangeHandler())
- )
- } else {
- router!!.setRoot(
- RouterTransaction.with(ServerSelectionController())
- .pushChangeHandler(HorizontalChangeHandler())
- .popChangeHandler(HorizontalChangeHandler())
- )
- }
- }
- override fun onStart() {
- Log.d(TAG, "onStart: Activity: " + System.identityHashCode(this).toString())
- super.onStart()
- logRouterBackStack(router!!)
- }
- override fun onResume() {
- Log.d(TAG, "onResume: Activity: " + System.identityHashCode(this).toString())
- super.onResume()
- if (appPreferences.isScreenLocked) {
- SecurityUtils.createKey(appPreferences.screenLockTimeout)
- }
- }
- override fun onPause() {
- Log.d(TAG, "onPause: Activity: " + System.identityHashCode(this).toString())
- super.onPause()
- }
- override fun onStop() {
- Log.d(TAG, "onStop: Activity: " + System.identityHashCode(this).toString())
- super.onStop()
- }
- private fun openConversationList() {
- val intent = Intent(this, ConversationsListActivity::class.java)
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
- intent.putExtras(Bundle())
- startActivity(intent)
- }
- fun addAccount() {
- router!!.pushController(
- RouterTransaction.with(ServerSelectionController())
- .pushChangeHandler(VerticalChangeHandler())
- .popChangeHandler(VerticalChangeHandler())
- )
- }
- private fun handleActionFromContact(intent: Intent) {
- if (intent.action == Intent.ACTION_VIEW && intent.data != null) {
- val cursor = contentResolver.query(intent.data!!, null, null, null, null)
- var userId = ""
- if (cursor != null) {
- if (cursor.moveToFirst()) {
- // userId @ server
- userId = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Data.DATA1))
- }
- cursor.close()
- }
- when (intent.type) {
- "vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat" -> {
- val user = userId.substringBeforeLast("@")
- val baseUrl = userId.substringAfterLast("@")
- if (userManager.currentUser.blockingGet()?.baseUrl?.endsWith(baseUrl) == true) {
- startConversation(user)
- } else {
- Snackbar.make(
- binding.controllerContainer,
- R.string.nc_phone_book_integration_account_not_found,
- Snackbar.LENGTH_LONG
- ).show()
- }
- }
- }
- }
- }
- private fun startConversation(userId: String) {
- val roomType = "1"
- val currentUser = userManager.currentUser.blockingGet()
- val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, 1))
- val credentials = ApiUtils.getCredentials(currentUser?.username, currentUser?.token)
- val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(
- apiVersion,
- currentUser?.baseUrl,
- roomType,
- null,
- userId,
- null
- )
- ncApi.createRoom(
- credentials,
- retrofitBucket.url,
- retrofitBucket.queryMap
- )
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(object : Observer<RoomOverall> {
- override fun onSubscribe(d: Disposable) {
- // unused atm
- }
- override fun onNext(roomOverall: RoomOverall) {
- val bundle = Bundle()
- bundle.putParcelable(KEY_USER_ENTITY, currentUser)
- bundle.putString(KEY_ROOM_TOKEN, roomOverall.ocs!!.data!!.token)
- bundle.putString(KEY_ROOM_ID, roomOverall.ocs!!.data!!.roomId)
- // FIXME once APIv2 or later is used only, the createRoom already returns all the data
- ncApi.getRoom(
- credentials,
- ApiUtils.getUrlForRoom(
- apiVersion,
- currentUser?.baseUrl,
- roomOverall.ocs!!.data!!.token
- )
- )
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(object : Observer<RoomOverall> {
- override fun onSubscribe(d: Disposable) {
- // unused atm
- }
- override fun onNext(roomOverall: RoomOverall) {
- bundle.putParcelable(
- KEY_ACTIVE_CONVERSATION,
- Parcels.wrap(roomOverall.ocs!!.data)
- )
- val chatIntent = Intent(context, ChatActivity::class.java)
- chatIntent.putExtras(bundle)
- startActivity(chatIntent)
- }
- override fun onError(e: Throwable) {
- // unused atm
- }
- override fun onComplete() {
- // unused atm
- }
- })
- }
- override fun onError(e: Throwable) {
- // unused atm
- }
- override fun onComplete() {
- // unused atm
- }
- })
- }
- override fun onNewIntent(intent: Intent) {
- super.onNewIntent(intent)
- Log.d(TAG, "onNewIntent Activity: " + System.identityHashCode(this).toString())
- val user = intent.getParcelableExtra<User>(KEY_USER_ENTITY)
- if (user != null && userManager.setUserAsActive(user).blockingGet()) {
- handleIntent(intent)
- }
- }
- private fun handleIntent(intent: Intent) {
- handleActionFromContact(intent)
- if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
- if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
- if (!router!!.hasRootController()) {
- openConversationList()
- }
- val callNotificationIntent = Intent(this, CallNotificationActivity::class.java)
- intent.extras?.let { callNotificationIntent.putExtras(it) }
- startActivity(callNotificationIntent)
- } else {
- logRouterBackStack(router!!)
- val chatIntent = Intent(context, ChatActivity::class.java)
- chatIntent.putExtras(intent.extras!!)
- startActivity(chatIntent)
- logRouterBackStack(router!!)
- }
- }
- }
- private fun logRouterBackStack(router: Router) {
- if (BuildConfig.DEBUG) {
- val backstack = router.backstack
- var routerTransaction: RouterTransaction?
- Log.d(TAG, " backstack size: " + router.backstackSize)
- for (i in 0 until router.backstackSize) {
- routerTransaction = backstack[i]
- Log.d(TAG, " controller: " + routerTransaction.controller)
- }
- }
- }
- companion object {
- private const val TAG = "MainActivity"
- }
- }
|