diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiClient.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiClient.kt index 6dd8bb8d6..0299fa4ac 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiClient.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/ApiClient.kt @@ -45,8 +45,11 @@ class ApiClient @Inject constructor( connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false return when { actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true + actNw.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true + actNw.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> true + actNw.hasTransport(NetworkCapabilities.TRANSPORT_USB) -> true else -> false } } @@ -115,9 +118,16 @@ class ApiClient @Inject constructor( .build() val response = chain.proceed(request) if (request.method == "GET") { - response.newBuilder() - .header("Cache-Control", request.header("Cache-Control") ?: "") - .build() + if (response.code == 504) { + // Cache miss. Network might be down, but retry call without cache to be sure. + chain.proceed(request.newBuilder() + .header("Cache-Control", "no-cache") + .build()) + } else { + response.newBuilder() + .header("Cache-Control", request.header("Cache-Control") ?: "") + .build() + } } else { response } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/modules/AppModule.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/modules/AppModule.kt index 0ce45f8fd..e2c2673c5 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/modules/AppModule.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/modules/AppModule.kt @@ -3,7 +3,9 @@ package com.habitrpg.wearos.habitica.modules import android.content.Context import android.content.SharedPreferences import androidx.preference.PreferenceManager +import com.habitrpg.android.habitica.BuildConfig import com.habitrpg.common.habitica.api.HostConfig +import com.habitrpg.common.habitica.helpers.AppTestingLevel import com.habitrpg.common.habitica.helpers.KeyHelper import com.habitrpg.shared.habitica.HLogger import com.habitrpg.wearos.habitica.data.ApiClient @@ -103,4 +105,10 @@ class AppModule { null } else KeyHelper.getInstance(context, sharedPreferences, keyStore) } + + @Provides + @Singleton + fun provideTestingLevel(): AppTestingLevel { + return AppTestingLevel.valueOf(BuildConfig.TESTING_LEVEL.uppercase()) + } } \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/LoginActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/LoginActivity.kt index cc5e5cb8e..4dd39bdcb 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/LoginActivity.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/LoginActivity.kt @@ -1,6 +1,5 @@ package com.habitrpg.wearos.habitica.ui.activities -import android.accounts.AccountManager import android.app.Activity import android.app.AlertDialog import android.content.Intent @@ -9,6 +8,7 @@ import android.text.method.PasswordTransformationMethod import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import androidx.core.view.isVisible +import com.google.android.gms.auth.api.signin.GoogleSignIn import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.databinding.ActivityLoginBinding import com.habitrpg.wearos.habitica.ui.viewmodels.LoginViewModel @@ -72,7 +72,7 @@ class LoginActivity: BaseActivity() { startMainActivity() } - binding.signInOnPhoneButton.setOnClickListener { } + binding.signInOnPhoneButton.setOnClickListener { openRegisterOnPhone() } binding.otherButton.setOnClickListener { currentState = State.OTHER } binding.usernamePasswordButton.setOnClickListener { currentState = State.INPUT } @@ -117,17 +117,16 @@ class LoginActivity: BaseActivity() { } private val pickAccountResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == Activity.RESULT_OK) { - viewModel.googleEmail = it?.data?.getStringExtra(AccountManager.KEY_ACCOUNT_NAME) - viewModel.handleGoogleLoginResult(this, recoverFromPlayServicesErrorResult) - } + val task = GoogleSignIn.getSignedInAccountFromIntent(it.data) + viewModel.handleGoogleLoginResult(this, task, recoverFromPlayServicesErrorResult) } private val recoverFromPlayServicesErrorResult = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { if (it.resultCode != Activity.RESULT_CANCELED) { - viewModel.handleGoogleLoginResult(this, null) + val task = GoogleSignIn.getSignedInAccountFromIntent(it.data) + viewModel.handleGoogleLoginResult(this, task, null) } } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/LoginViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/LoginViewModel.kt index 6f449df4e..40b0396a0 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/LoginViewModel.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/LoginViewModel.kt @@ -1,36 +1,42 @@ package com.habitrpg.wearos.habitica.ui.viewmodels -import android.accounts.AccountManager import android.app.Activity -import android.content.ActivityNotFoundException import android.content.Intent import android.content.SharedPreferences import androidx.activity.result.ActivityResultLauncher import androidx.core.content.edit import androidx.lifecycle.viewModelScope import com.google.android.gms.auth.GoogleAuthException -import com.google.android.gms.auth.GoogleAuthUtil import com.google.android.gms.auth.GooglePlayServicesAvailabilityException import com.google.android.gms.auth.UserRecoverableAuthException +import com.google.android.gms.auth.api.signin.GoogleSignIn +import com.google.android.gms.auth.api.signin.GoogleSignInAccount +import com.google.android.gms.auth.api.signin.GoogleSignInOptions import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GoogleApiAvailability import com.google.android.gms.common.GooglePlayServicesUtil import com.google.android.gms.common.Scopes import com.google.android.gms.common.UserRecoverableException +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.tasks.Task import com.habitrpg.common.habitica.helpers.KeyHelper import com.habitrpg.common.habitica.models.auth.UserAuth import com.habitrpg.common.habitica.models.auth.UserAuthResponse import com.habitrpg.common.habitica.models.auth.UserAuthSocial +import com.habitrpg.common.habitica.models.auth.UserAuthSocialTokens import com.habitrpg.wearos.habitica.data.ApiClient import com.habitrpg.wearos.habitica.data.repositories.UserRepository import com.habitrpg.wearos.habitica.managers.LoadingManager import com.habitrpg.wearos.habitica.util.ExceptionHandlerBuilder import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async import kotlinx.coroutines.launch import java.io.IOException import javax.inject.Inject + + + @HiltViewModel class LoginViewModel @Inject constructor(userRepository: UserRepository, exceptionBuilder: ExceptionHandlerBuilder, @@ -39,53 +45,48 @@ class LoginViewModel @Inject constructor(userRepository: UserRepository, val apiClient: ApiClient, loadingManager: LoadingManager ) : BaseViewModel(userRepository, exceptionBuilder, loadingManager) { lateinit var onLoginCompleted: () -> Unit - var googleEmail: String? = null fun handleGoogleLogin( activity: Activity, pickAccountResult: ActivityResultLauncher ) { - if (!checkPlayServices(activity)) { - return - } - val accountTypes = arrayOf("com.google") - val intent = AccountManager.newChooseAccountIntent( - null, null, - accountTypes, true, null, null, null, null - ) - try { - pickAccountResult.launch(intent) - } catch (e: ActivityNotFoundException) { - /*val alert = AlertDialog.Builder(activity).create() - alert.setTitle(R.string.authentication_error_title) - alert.setMessage(R.string.google_services_missing) - alert.addCloseButton() - alert.show()*/ - } + val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail() + .build() + val client = GoogleSignIn.getClient(activity, gso) + pickAccountResult.launch(client.signInIntent) } fun handleGoogleLoginResult( activity: Activity, + task: Task, recoverFromPlayServicesErrorResult: ActivityResultLauncher?, ) { val scopesString = Scopes.PROFILE + " " + Scopes.EMAIL - val scopes = "oauth2:$scopesString" viewModelScope.launch(exceptionBuilder.userFacing(this)) { - val token = launch(Dispatchers.IO) { + val account = async { try { - GoogleAuthUtil.getToken(activity, googleEmail ?: "", scopes) + val account: GoogleSignInAccount = task.getResult( + ApiException::class.java + ) + return@async account } catch (e: IOException) { - return@launch + return@async null } catch (e: GoogleAuthException) { if (recoverFromPlayServicesErrorResult != null) { handleGoogleAuthException(e, activity, recoverFromPlayServicesErrorResult) } - return@launch + return@async null } catch (e: UserRecoverableException) { - return@launch + return@async null } - } - val response = apiClient.loginSocial(UserAuthSocial()) + }.await() + val auth = UserAuthSocial() + auth.network = "google" + auth.authResponse = UserAuthSocialTokens() + auth.authResponse?.client_id = account?.id + auth.authResponse?.access_token = account?.idToken + val response = apiClient.loginSocial(auth) handleAuthResponse(response) } } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/RYAViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/RYAViewModel.kt index f2779520c..6e23595a6 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/RYAViewModel.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/RYAViewModel.kt @@ -27,9 +27,10 @@ class RYAViewModel @Inject constructor( init { viewModelScope.launch(exceptionBuilder.silent()) { - tasks.value = taskRepository.getTasks(TaskType.DAILY) + val taskList: List = taskRepository.getTasks(TaskType.DAILY) .map { it.filter { task -> task.isDue == true && !task.completed } } .first() + tasks.value = taskList } }