diff --git a/app/src/main/java/foundation/e/accountmanager/Constants.kt b/app/src/main/java/foundation/e/accountmanager/Constants.kt index 48124751d348190535f59026e016df4dcbdd8c84..5619fde74f84559fb5d85db56b3f76e85fdb2d22 100644 --- a/app/src/main/java/foundation/e/accountmanager/Constants.kt +++ b/app/src/main/java/foundation/e/accountmanager/Constants.kt @@ -31,5 +31,7 @@ object Constants { const val AUTH_TOKEN_TYPE = "oauth2-access-token" - const val EELO_SYNC_URL = "https://ecloud.global" + const val EELO_SYNC_SCHEME = "https://" + const val EELO_SYNC_HOST = "ecloud.global" + const val EELO_SYNC_URL = EELO_SYNC_SCHEME + EELO_SYNC_HOST } diff --git a/app/src/main/java/foundation/e/accountmanager/ECloudAccountHelper.kt b/app/src/main/java/foundation/e/accountmanager/ECloudAccountHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..c49274a76e111702ca37b65c1dffa383c7c1db97 --- /dev/null +++ b/app/src/main/java/foundation/e/accountmanager/ECloudAccountHelper.kt @@ -0,0 +1,26 @@ +package foundation.e.accountmanager + +import android.accounts.AccountManager +import android.app.Activity +import android.content.Context +import com.google.android.material.dialog.MaterialAlertDialogBuilder + +object ECloudAccountHelper { + + fun alreadyHasECloudAccount(context: Context) : Boolean { + val accountManager = AccountManager.get(context) + val eCloudAccounts = accountManager.getAccountsByType(context.getString(R.string.eelo_account_type)) + return eCloudAccounts.isNotEmpty() + } + + fun showMultipleECloudAccountNotAcceptedDialog(activity: Activity) { + MaterialAlertDialogBuilder(activity, R.style.CustomAlertDialogStyle) + .setIcon(R.drawable.ic_error_dark) + .setMessage(R.string.multiple_ecloud_account_not_permitted_message) + .setCancelable(false) + .setPositiveButton(android.R.string.ok) { _, _ -> + activity.finish() + } + .show() + } +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/accountmanager/ui/AccountListFragment.kt b/app/src/main/java/foundation/e/accountmanager/ui/AccountListFragment.kt index 2e8a7abe39998efc885e604da899796343df2b72..bbbd961387f16754b5acd46e5c95153b8bab707b 100644 --- a/app/src/main/java/foundation/e/accountmanager/ui/AccountListFragment.kt +++ b/app/src/main/java/foundation/e/accountmanager/ui/AccountListFragment.kt @@ -38,7 +38,7 @@ import foundation.e.accountmanager.ui.account.AccountActivity import kotlinx.android.synthetic.main.account_list.* import kotlinx.android.synthetic.main.account_list_item.view.* -class AccountListFragment: ListFragment() { +class AccountListFragment : ListFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { listAdapter = AccountListAdapter(requireActivity()) @@ -74,12 +74,13 @@ class AccountListFragment: ListFragment() { class AccountListAdapter( context: Context - ): ArrayAdapter(context, R.layout.account_list_item) { + ) : ArrayAdapter(context, R.layout.account_list_item) { override fun getView(position: Int, _v: View?, parent: ViewGroup): View { val account = getItem(position)!! - val v = _v ?: LayoutInflater.from(context).inflate(R.layout.account_list_item, parent, false) + val v = _v + ?: LayoutInflater.from(context).inflate(R.layout.account_list_item, parent, false) v.account_name.text = account.name return v @@ -89,7 +90,7 @@ class AccountListFragment: ListFragment() { class Model( application: Application - ): AndroidViewModel(application), OnAccountsUpdateListener { + ) : AndroidViewModel(application), OnAccountsUpdateListener { val accounts = MutableLiveData>() @@ -99,11 +100,12 @@ class AccountListFragment: ListFragment() { private val accountManager = AccountManager.get(getApplication())!! private val connectivityManager = application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + init { accountManager.addOnAccountsUpdatedListener(this, null, true) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // API level <26 - networkReceiver = object: BroadcastReceiver() { + networkReceiver = object : BroadcastReceiver() { init { update() } @@ -124,7 +126,7 @@ class AccountListFragment: ListFragment() { .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) .build() - val callback = object: ConnectivityManager.NetworkCallback() { + val callback = object : ConnectivityManager.NetworkCallback() { val availableNetworks = hashSetOf() override fun onAvailable(network: Network) { @@ -153,7 +155,6 @@ class AccountListFragment: ListFragment() { networkReceiver?.let { getApplication().unregisterReceiver(it) } - else networkCallback?.let { connectivityManager.unregisterNetworkCallback(it) @@ -163,14 +164,14 @@ class AccountListFragment: ListFragment() { override fun onAccountsUpdated(newAccounts: Array) { val context = getApplication() - val account = ArrayList() + val account = ArrayList() val accountManager = AccountManager.get(context) accountManager.getAccountsByType(context.getString(R.string.eelo_account_type)).forEach { account.add(it) } accountManager.getAccountsByType(context.getString(R.string.google_account_type)).forEach { account.add(it) } accountManager.getAccountsByType(context.getString(R.string.account_type)).forEach { account.add(it) } accounts.postValue( - account.toTypedArray() + account.toTypedArray() ) } diff --git a/app/src/main/java/foundation/e/accountmanager/ui/setup/DetectConfigurationFragment.kt b/app/src/main/java/foundation/e/accountmanager/ui/setup/DetectConfigurationFragment.kt index f124a460d20f2e4d2f641e0c88588808c8cf3664..de7266ae444e480f70744cd6c74d14e7ef6e2524 100644 --- a/app/src/main/java/foundation/e/accountmanager/ui/setup/DetectConfigurationFragment.kt +++ b/app/src/main/java/foundation/e/accountmanager/ui/setup/DetectConfigurationFragment.kt @@ -22,6 +22,8 @@ import foundation.e.accountmanager.R import foundation.e.accountmanager.log.Logger import foundation.e.accountmanager.ui.DebugInfoActivity import com.google.android.material.dialog.MaterialAlertDialogBuilder +import foundation.e.accountmanager.Constants +import foundation.e.accountmanager.ECloudAccountHelper import java.lang.ref.WeakReference import java.util.logging.Level import kotlin.concurrent.thread @@ -36,6 +38,11 @@ class DetectConfigurationFragment: Fragment() { loginModel = ViewModelProviders.of(requireActivity()).get(LoginModel::class.java) model = ViewModelProviders.of(this).get(DetectConfigurationModel::class.java) + if (model.blockProceedWithLogin(loginModel)) { + ECloudAccountHelper.showMultipleECloudAccountNotAcceptedDialog(requireActivity()) + return; + } + model.detectConfiguration(loginModel).observe(this, Observer { result -> // save result for next step loginModel.configuration = result @@ -66,6 +73,16 @@ class DetectConfigurationFragment: Fragment() { private var detectionThread: WeakReference? = null private var result = MutableLiveData() + /** + * User can't login using multiple ecloud accounts. + * This method checks if the login host is eelo_host then, check user already has any eelo account set up. + * If found eCloundAccount return true, false otherwise. + */ + fun blockProceedWithLogin(loginModel: LoginModel) : Boolean { + val context = getApplication() + return (loginModel.baseURI?.host.equals(Constants.EELO_SYNC_HOST) && ECloudAccountHelper.alreadyHasECloudAccount(context)) + } + fun detectConfiguration(loginModel: LoginModel): LiveData { synchronized(result) { if (detectionThread != null) diff --git a/app/src/main/java/foundation/e/accountmanager/ui/setup/EeloAuthenticatorFragment.kt b/app/src/main/java/foundation/e/accountmanager/ui/setup/EeloAuthenticatorFragment.kt index 7f4f82e0f11b739962245682b650f9a47fd1e91e..b5399fdb093004c097d7937be780abed3418f38f 100644 --- a/app/src/main/java/foundation/e/accountmanager/ui/setup/EeloAuthenticatorFragment.kt +++ b/app/src/main/java/foundation/e/accountmanager/ui/setup/EeloAuthenticatorFragment.kt @@ -1,39 +1,32 @@ package foundation.e.accountmanager.ui.setup import android.content.Context -import android.net.MailTo -import android.os.* -import androidx.fragment.app.Fragment +import android.net.ConnectivityManager +import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast -import android.net.Uri -import android.net.ConnectivityManager - -import foundation.e.accountmanager.R +import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProviders -import org.json.JSONObject +import foundation.e.accountmanager.ECloudAccountHelper +import foundation.e.accountmanager.R import foundation.e.accountmanager.databinding.FragmentEeloAuthenticatorBinding +import foundation.e.accountmanager.model.Credentials import kotlinx.android.synthetic.main.fragment_eelo_authenticator.* -import foundation.e.dav4jvm.Constants import kotlinx.android.synthetic.main.fragment_eelo_authenticator.view.* -import java.net.IDN import java.net.URI -import java.net.URISyntaxException -import java.util.logging.Level -import foundation.e.accountmanager.model.Credentials class EeloAuthenticatorFragment : Fragment() { - private lateinit var model: EeloAuthenticatorModel + private lateinit var model: EeloAuthenticatorModel private lateinit var loginModel: LoginModel val TOGGLE_BUTTON_CHECKED_KEY = "toggle_button_checked" var toggleButtonState = false private fun isNetworkAvailable(): Boolean { - val connectivityManager = activity!!.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val connectivityManager = requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val activeNetworkInfo = connectivityManager.activeNetworkInfo return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting } @@ -41,46 +34,46 @@ class EeloAuthenticatorFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - model = ViewModelProviders.of(this).get(EeloAuthenticatorModel::class.java) + model = ViewModelProviders.of(this).get(EeloAuthenticatorModel::class.java) loginModel = ViewModelProviders.of(requireActivity()).get(LoginModel::class.java) - if (!isNetworkAvailable()) { + if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() - activity!!.finish() + requireActivity().finish() } - val v = FragmentEeloAuthenticatorBinding.inflate(inflater, container, false) + val v = FragmentEeloAuthenticatorBinding.inflate(inflater, container, false) v.lifecycleOwner = this v.model = model - v.root.urlpwd_other_account_title_panel.setOnClickListener() { expandCollapse() } + v.root.urlpwd_other_account_title_panel.setOnClickListener() { expandCollapse() } - v.root.urlpwd_user_name.setOnFocusChangeListener() { v, hasFocus -> - if (!hasFocus ) { + v.root.urlpwd_user_name.setOnFocusChangeListener() { v, hasFocus -> + if (!hasFocus) { if (v.urlpwd_user_name.text.toString().contains("@")) { val dns = v.urlpwd_user_name.text.toString().substringAfter("@") val pre_custom_url = "https://" + dns - view!!.urlpwd_server_uri.setText(pre_custom_url) + requireView().urlpwd_server_uri.setText(pre_custom_url) } else { - view!!.urlpwd_server_uri.setText("") + requireView().urlpwd_server_uri.setText("") } } } - v.login.setOnClickListener { login() } + v.login.setOnClickListener { login() } - // code below is to draw toggle button in its correct state and show or hide server url input field + // code below is to draw toggle button in its correct state and show or hide server url input field //add by Vincent, 18/02/2019 - if(savedInstanceState != null){ + if (savedInstanceState != null) { toggleButtonState = savedInstanceState.getBoolean(TOGGLE_BUTTON_CHECKED_KEY, false) } - - //This allow the button to be redraw in the correct state if user turn screen - if(toggleButtonState == true) { + + //This allow the button to be redraw in the correct state if user turn screen + if (toggleButtonState == true) { v.root.expand_collapse_button.setChecked(toggleButtonState) v.root.urlpwd_server_uri_layout.setVisibility(View.VISIBLE) v.root.urlpwd_server_uri.setEnabled(true) - }else{ + } else { v.root.urlpwd_server_uri_layout.setVisibility(View.GONE) v.root.urlpwd_server_uri.setEnabled(false) } @@ -88,6 +81,13 @@ class EeloAuthenticatorFragment : Fragment() { return v.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + if (model.blockProceedWithLogin()) { + ECloudAccountHelper.showMultipleECloudAccountNotAcceptedDialog(requireActivity()) + } + } + override fun onSaveInstanceState(outState: Bundle) { outState.putBoolean(TOGGLE_BUTTON_CHECKED_KEY, toggleButtonState) super.onSaveInstanceState(outState) @@ -96,17 +96,17 @@ class EeloAuthenticatorFragment : Fragment() { private fun login() { if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() - activity!!.finish() + requireActivity().finish() } - - if ((urlpwd_user_name.text.toString() != "") && (urlpwd_password.text.toString() != "")) { - if (validate()) - requireFragmentManager().beginTransaction() + + if ((urlpwd_user_name.text.toString() != "") && (urlpwd_password.text.toString() != "")) { + if (validate()) + requireFragmentManager().beginTransaction() .replace(android.R.id.content, DetectConfigurationFragment(), null) - .addToBackStack(null) - .commit() - } else { - Toast.makeText(context, "Please enter a valid username and password", Toast.LENGTH_LONG).show() + .addToBackStack(null) + .commit() + } else { + Toast.makeText(context, "Please enter a valid username and password", Toast.LENGTH_LONG).show() } } @@ -114,14 +114,14 @@ class EeloAuthenticatorFragment : Fragment() { private fun validate(): Boolean { var valid = false - var serverUrl = foundation.e.accountmanager.Constants.EELO_SYNC_URL + var serverUrl = foundation.e.accountmanager.Constants.EELO_SYNC_URL fun validateUrl() { - if(toggleButtonState == true) { - serverUrl = view!!.urlpwd_server_uri.text.toString(); + if (toggleButtonState == true) { + serverUrl = requireView().urlpwd_server_uri.text.toString(); } else { - serverUrl = foundation.e.accountmanager.Constants.EELO_SYNC_URL + serverUrl = foundation.e.accountmanager.Constants.EELO_SYNC_URL } model.baseUrlError.value = null @@ -139,17 +139,17 @@ class EeloAuthenticatorFragment : Fragment() { when { - model.loginWithUrlAndTokens.value == true -> { - validateUrl() + model.loginWithUrlAndTokens.value == true -> { + validateUrl() - val userName = view!!.urlpwd_user_name.text.toString() - val password = view!!.urlpwd_password.text.toString() + val userName = requireView().urlpwd_user_name.text.toString() + val password = requireView().urlpwd_password.text.toString() - if (loginModel.baseURI != null) { - valid = true - loginModel.credentials = Credentials(userName.toLowerCase(), password, null, null, loginModel.baseURI) - } - } + if (loginModel.baseURI != null) { + valid = true + loginModel.credentials = Credentials(userName.toLowerCase(), password, null, null, loginModel.baseURI) + } + } } @@ -159,16 +159,15 @@ class EeloAuthenticatorFragment : Fragment() { /** * Show/Hide panel containing server's uri input field. */ - private fun expandCollapse(){ - //inverse state of Toggle button + private fun expandCollapse() { + //inverse state of Toggle button expand_collapse_button.setChecked(!expand_collapse_button.isChecked()) - if(expand_collapse_button.isChecked) { + if (expand_collapse_button.isChecked) { urlpwd_server_uri_layout.setVisibility(View.VISIBLE) urlpwd_server_uri.setEnabled(true) toggleButtonState = true; - } - else { + } else { urlpwd_server_uri_layout.setVisibility(View.GONE) urlpwd_server_uri.setEnabled(false) toggleButtonState = false; diff --git a/app/src/main/java/foundation/e/accountmanager/ui/setup/EeloAuthenticatorModel.kt b/app/src/main/java/foundation/e/accountmanager/ui/setup/EeloAuthenticatorModel.kt index 60f4abbdf99d613276f14a75be37c2997348ceab..9deddfba95302173b232007d71133f502b654c10 100644 --- a/app/src/main/java/foundation/e/accountmanager/ui/setup/EeloAuthenticatorModel.kt +++ b/app/src/main/java/foundation/e/accountmanager/ui/setup/EeloAuthenticatorModel.kt @@ -1,16 +1,17 @@ package foundation.e.accountmanager.ui.setup +import android.app.Application import android.content.Intent -import android.net.Uri +import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel +import foundation.e.accountmanager.ECloudAccountHelper -class EeloAuthenticatorModel: ViewModel() { +class EeloAuthenticatorModel(application: Application) : AndroidViewModel(application) { private var initialized = false val loginWithUrlAndTokens = MutableLiveData() - + val baseUrl = MutableLiveData() val baseUrlError = MutableLiveData() @@ -19,7 +20,7 @@ class EeloAuthenticatorModel: ViewModel() { val username = MutableLiveData() val usernameError = MutableLiveData() - + val password = MutableLiveData() val passwordError = MutableLiveData() @@ -27,7 +28,7 @@ class EeloAuthenticatorModel: ViewModel() { val certificateAliasError = MutableLiveData() init { - loginWithUrlAndTokens.value = true + loginWithUrlAndTokens.value = true } fun initialize(intent: Intent) { @@ -36,15 +37,21 @@ class EeloAuthenticatorModel: ViewModel() { // we've got initial login data val givenUrl = intent.getStringExtra(LoginActivity.EXTRA_URL) - val givenUsername = intent.getStringExtra(LoginActivity.EXTRA_USERNAME) + val givenUsername = intent.getStringExtra(LoginActivity.EXTRA_USERNAME) val givenPassword = intent.getStringExtra(LoginActivity.EXTRA_PASSWORD) - baseUrl.value = givenUrl - + baseUrl.value = givenUrl + password.value = givenPassword initialized = true } + + fun blockProceedWithLogin(): Boolean { + val context = getApplication() + return ECloudAccountHelper.alreadyHasECloudAccount(context) + } + } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3af4065e4c6a4a2b228f32a886b73e1522e9077c..1c3951fcd2d32a80e970c50965b57c7e56297c87 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -354,4 +354,5 @@ My Profile Shows Data about account + You can configure only one ecloud account on your device