diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4e41dd302..e4e547aab 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -90,8 +90,6 @@ - - diff --git a/app/src/main/java/com/aurora/store/view/ui/account/AccountFragment.kt b/app/src/main/java/com/aurora/store/view/ui/account/AccountFragment.kt index f23f28cfb..f75995c1b 100644 --- a/app/src/main/java/com/aurora/store/view/ui/account/AccountFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/account/AccountFragment.kt @@ -201,7 +201,7 @@ class AccountFragment : Fragment(R.layout.fragment_account) { binding.btnGoogle.addOnClickListener { if (VM.liveData.value != AuthState.Fetching) { binding.btnGoogle.updateProgress(true) - val intent = Intent(requireContext(), GoogleActivity::class.java) + val intent = Intent(requireContext(), GoogleFragment::class.java) startForResult.launch(intent, requireContext().getEmptyActivityAnimation()) } } diff --git a/app/src/main/java/com/aurora/store/view/ui/account/GoogleActivity.kt b/app/src/main/java/com/aurora/store/view/ui/account/GoogleActivity.kt deleted file mode 100644 index 069ad2657..000000000 --- a/app/src/main/java/com/aurora/store/view/ui/account/GoogleActivity.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2021, Rahul Kumar Patel - * - * Aurora Store 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 2 of the License, or - * (at your option) any later version. - * - * Aurora Store 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 Aurora Store. If not, see . - * - */ - -package com.aurora.store.view.ui.account - -import android.annotation.SuppressLint -import android.os.Build -import android.os.Bundle -import android.webkit.CookieManager -import android.webkit.WebSettings -import android.webkit.WebView -import android.webkit.WebViewClient -import android.widget.Toast -import com.aurora.Constants -import com.aurora.store.R -import com.aurora.store.data.event.BusEvent -import com.aurora.store.databinding.ActivityGoogleBinding -import com.aurora.store.util.AC2DMTask -import com.aurora.store.util.AC2DMUtil -import com.aurora.store.util.Preferences -import com.aurora.store.view.ui.commons.BaseActivity -import nl.komponents.kovenant.task -import org.greenrobot.eventbus.EventBus - -class GoogleActivity : BaseActivity() { - - private lateinit var B: ActivityGoogleBinding - - private val cookieManager = CookieManager.getInstance() - - override fun onConnected() { - } - - override fun onDisconnected() { - showNetworkConnectivitySheet() - } - - override fun onReconnected() { - hideNetworkConnectivitySheet() - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - B = ActivityGoogleBinding.inflate(layoutInflater) - setContentView(B.root) - - setupWebView() - } - - @SuppressLint("SetJavaScriptEnabled") - private fun setupWebView() { - cookieManager.removeAllCookies(null) - cookieManager.acceptThirdPartyCookies(B.webview) - cookieManager.setAcceptThirdPartyCookies(B.webview, true) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - B.webview.settings.safeBrowsingEnabled = false - } - - B.webview.webViewClient = object : WebViewClient() { - override fun onPageFinished(view: WebView, url: String) { - val cookies = CookieManager.getInstance().getCookie(url) - val cookieMap = AC2DMUtil.parseCookieString(cookies) - if (cookieMap.isNotEmpty() && cookieMap[AUTH_TOKEN] != null) { - val oauthToken = cookieMap[AUTH_TOKEN] - B.webview.evaluateJavascript("(function() { return document.getElementById('profileIdentifier').innerHTML; })();") { - val email = it.replace("\"".toRegex(), "") - buildAuthData(email, oauthToken) - } - } - } - } - - B.webview.apply { - settings.apply { - allowContentAccess = true - databaseEnabled = true - domStorageEnabled = true - javaScriptEnabled = true - cacheMode = WebSettings.LOAD_DEFAULT - } - loadUrl(EMBEDDED_SETUP_URL) - } - } - - private fun buildAuthData(email: String, oauthToken: String?) { - task { - AC2DMTask().getAC2DMResponse(email, oauthToken) - } success { - if (it.isNotEmpty()) { - val aasToken = it["Token"] - if (aasToken != null) { - Preferences.putString(this, Constants.ACCOUNT_EMAIL_PLAIN, email) - Preferences.putString(this, Constants.ACCOUNT_AAS_PLAIN, aasToken) - EventBus.getDefault().post(BusEvent.GoogleAAS(true, email, aasToken)) - } else { - Preferences.putString(this, Constants.ACCOUNT_EMAIL_PLAIN, "") - Preferences.putString(this, Constants.ACCOUNT_AAS_PLAIN, "") - EventBus.getDefault().post(BusEvent.GoogleAAS(false)) - } - } else { - Toast.makeText(this, getString(R.string.toast_aas_token_failed), Toast.LENGTH_LONG) - .show() - EventBus.getDefault().post(BusEvent.GoogleAAS(false)) - } - - //Close Activity - setResult(RESULT_OK) - finishAfterTransition() - } fail { - Toast.makeText(this, getString(R.string.toast_aas_token_failed), Toast.LENGTH_LONG) - .show() - EventBus.getDefault().post(BusEvent.GoogleAAS(false)) - - //Close Activity - setResult(RESULT_CANCELED) - finishAfterTransition() - } - } - - companion object { - const val EMBEDDED_SETUP_URL = - "https://accounts.google.com/EmbeddedSetup/identifier?flowName=EmbeddedSetupAndroid" - const val AUTH_TOKEN = "oauth_token" - } -} diff --git a/app/src/main/java/com/aurora/store/view/ui/account/GoogleFragment.kt b/app/src/main/java/com/aurora/store/view/ui/account/GoogleFragment.kt new file mode 100644 index 000000000..337205f78 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/ui/account/GoogleFragment.kt @@ -0,0 +1,136 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store 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 2 of the License, or + * (at your option) any later version. + * + * Aurora Store 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 Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.account + +import android.os.Build +import android.os.Bundle +import android.view.View +import android.webkit.CookieManager +import android.webkit.WebSettings +import android.webkit.WebView +import android.webkit.WebViewClient +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.navigation.fragment.findNavController +import com.aurora.Constants +import com.aurora.store.R +import com.aurora.store.data.event.BusEvent +import com.aurora.store.databinding.FragmentGoogleBinding +import com.aurora.store.util.AC2DMTask +import com.aurora.store.util.AC2DMUtil +import com.aurora.store.util.Preferences +import com.aurora.store.viewmodel.auth.AuthViewModel +import nl.komponents.kovenant.task +import org.greenrobot.eventbus.EventBus + +class GoogleFragment : Fragment(R.layout.fragment_google) { + + private val viewModel: AuthViewModel by activityViewModels() + + companion object { + const val EMBEDDED_SETUP_URL = + "https://accounts.google.com/EmbeddedSetup/identifier?flowName=EmbeddedSetupAndroid" + const val AUTH_TOKEN = "oauth_token" + private const val JS_SCRIPT = + "(function() { return document.getElementById('profileIdentifier').innerHTML; })();" + } + + private var _binding: FragmentGoogleBinding? = null + private val binding: FragmentGoogleBinding + get() = _binding!! + + private val cookieManager = CookieManager.getInstance() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + _binding = FragmentGoogleBinding.bind(view) + + binding.webview.apply { + cookieManager.removeAllCookies(null) + cookieManager.acceptThirdPartyCookies(this) + cookieManager.setAcceptThirdPartyCookies(this, true) + + webViewClient = object : WebViewClient() { + override fun onPageFinished(view: WebView, url: String) { + val cookies = CookieManager.getInstance().getCookie(url) + val cookieMap = AC2DMUtil.parseCookieString(cookies) + if (cookieMap.isNotEmpty() && cookieMap[AUTH_TOKEN] != null) { + val oauthToken = cookieMap[AUTH_TOKEN] + evaluateJavascript(JS_SCRIPT) { + val email = it.replace("\"".toRegex(), "") + buildAuthData(email, oauthToken) + } + } + } + } + + settings.apply { + allowContentAccess = true + databaseEnabled = true + domStorageEnabled = true + javaScriptEnabled = true + cacheMode = WebSettings.LOAD_DEFAULT + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) safeBrowsingEnabled = false + } + loadUrl(EMBEDDED_SETUP_URL) + } + } + + private fun buildAuthData(email: String, oauthToken: String?) { + task { + AC2DMTask().getAC2DMResponse(email, oauthToken) + } success { + if (it.isNotEmpty()) { + val aasToken = it["Token"] + if (aasToken != null) { + Preferences.putString(requireContext(), Constants.ACCOUNT_EMAIL_PLAIN, email) + Preferences.putString(requireContext(), Constants.ACCOUNT_AAS_PLAIN, aasToken) + EventBus.getDefault().post(BusEvent.GoogleAAS(true, email, aasToken)) + viewModel.buildGoogleAuthData(email, aasToken) + } else { + Preferences.putString(requireContext(), Constants.ACCOUNT_EMAIL_PLAIN, "") + Preferences.putString(requireContext(), Constants.ACCOUNT_AAS_PLAIN, "") + EventBus.getDefault().post(BusEvent.GoogleAAS(false)) + } + } else { + Toast.makeText( + requireContext(), + getString(R.string.toast_aas_token_failed), + Toast.LENGTH_LONG + ).show() + EventBus.getDefault().post(BusEvent.GoogleAAS(false)) + } + findNavController().navigate( + GoogleFragmentDirections.actionGoogleFragmentToSplashFragment() + ) + } fail { + Toast.makeText( + requireContext(), + getString(R.string.toast_aas_token_failed), + Toast.LENGTH_LONG + ).show() + EventBus.getDefault().post(BusEvent.GoogleAAS(false)) + findNavController().navigate( + GoogleFragmentDirections.actionGoogleFragmentToSplashFragment() + ) + } + } +} diff --git a/app/src/main/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/main/java/com/aurora/store/view/ui/splash/SplashFragment.kt index e952dd1ae..0e301ff42 100644 --- a/app/src/main/java/com/aurora/store/view/ui/splash/SplashFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/splash/SplashFragment.kt @@ -19,15 +19,11 @@ package com.aurora.store.view.ui.splash -import android.app.Activity.RESULT_CANCELED -import android.content.Intent import android.os.Bundle import android.view.View -import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider +import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController -import com.aurora.extensions.getEmptyActivityAnimation import com.aurora.extensions.hide import com.aurora.extensions.load import com.aurora.extensions.show @@ -35,7 +31,6 @@ import com.aurora.store.R import com.aurora.store.data.AuthState import com.aurora.store.data.event.BusEvent import com.aurora.store.databinding.FragmentSplashBinding -import com.aurora.store.view.ui.account.GoogleActivity import com.aurora.store.viewmodel.auth.AuthViewModel import com.bumptech.glide.load.resource.bitmap.RoundedCorners import org.greenrobot.eventbus.EventBus @@ -47,21 +42,11 @@ class SplashFragment : Fragment(R.layout.fragment_splash) { private val binding: FragmentSplashBinding get() = _binding!! - private lateinit var VM: AuthViewModel - - private val startForResult = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == RESULT_CANCELED) { - resetActions() - } else { - binding.btnGoogle.updateProgress(true) - } - } + private val viewModel: AuthViewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) _binding = FragmentSplashBinding.bind(view) - VM = ViewModelProvider(this)[AuthViewModel::class.java] binding.imgIcon.load(R.drawable.ic_logo) { transform(RoundedCorners(32)) @@ -75,7 +60,7 @@ class SplashFragment : Fragment(R.layout.fragment_splash) { //Initial status updateStatus(getString(R.string.session_init)) - VM.liveData.observe(viewLifecycleOwner) { + viewModel.liveData.observe(viewLifecycleOwner) { when (it) { AuthState.Fetching -> { updateStatus(getString(R.string.requesting_new_session)) @@ -114,11 +99,9 @@ class SplashFragment : Fragment(R.layout.fragment_splash) { } } } - } - override fun onResume() { - if (::VM.isInitialized) VM.observe() - super.onResume() + // Check authentication status + viewModel.observe() } override fun onDestroyView() { @@ -133,7 +116,7 @@ class SplashFragment : Fragment(R.layout.fragment_splash) { is BusEvent.GoogleAAS -> { if (event.success) { updateStatus(getString(R.string.session_verifying_google)) - VM.buildGoogleAuthData(event.email, event.aasToken) + viewModel.buildGoogleAuthData(event.email, event.aasToken) } else { updateStatus(getString(R.string.session_login_failed_google)) } @@ -163,24 +146,23 @@ class SplashFragment : Fragment(R.layout.fragment_splash) { private fun attachActions() { binding.btnAnonymous.addOnClickListener { - if (VM.liveData.value != AuthState.Fetching) { + if (viewModel.liveData.value != AuthState.Fetching) { binding.btnAnonymous.updateProgress(true) - VM.buildAnonymousAuthData() + viewModel.buildAnonymousAuthData() } } binding.btnAnonymousInsecure.addOnClickListener { - if (VM.liveData.value != AuthState.Fetching) { + if (viewModel.liveData.value != AuthState.Fetching) { binding.btnAnonymousInsecure.updateProgress(true) - VM.buildInSecureAnonymousAuthData() + viewModel.buildInSecureAnonymousAuthData() } } binding.btnGoogle.addOnClickListener { - if (VM.liveData.value != AuthState.Fetching) { + if (viewModel.liveData.value != AuthState.Fetching) { binding.btnGoogle.updateProgress(true) - val intent = Intent(requireContext(), GoogleActivity::class.java) - startForResult.launch(intent, activity?.getEmptyActivityAnimation()) + findNavController().navigate(R.id.googleFragment) } } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt index 741c43cbe..067b09d79 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/auth/AuthViewModel.kt @@ -59,17 +59,19 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application } override fun observe() { - val signedIn = Preferences.getBoolean(getApplication(), Constants.ACCOUNT_SIGNED_IN) - if (signedIn) { - liveData.postValue(AuthState.Available) - buildSavedAuthData() - } else { - liveData.postValue(AuthState.Unavailable) + if (liveData.value != AuthState.Fetching) { + val signedIn = Preferences.getBoolean(getApplication(), Constants.ACCOUNT_SIGNED_IN) + if (signedIn) { + liveData.postValue(AuthState.Available) + buildSavedAuthData() + } else { + liveData.postValue(AuthState.Unavailable) + } } } fun buildGoogleAuthData(email: String, aasToken: String) { - updateStatus("Requesting new session") + liveData.postValue(AuthState.Fetching) task { var properties = NativeDeviceInfoProvider(getApplication()).getNativeDeviceProperties() diff --git a/app/src/main/res/layout/activity_google.xml b/app/src/main/res/layout/fragment_google.xml similarity index 88% rename from app/src/main/res/layout/activity_google.xml rename to app/src/main/res/layout/fragment_google.xml index 25126cee3..b0b189138 100644 --- a/app/src/main/res/layout/activity_google.xml +++ b/app/src/main/res/layout/fragment_google.xml @@ -18,8 +18,10 @@ --> + android:layout_height="match_parent" + tools:context=".view.ui.account.GoogleFragment"> + + +