Twidere-App-Android-Twitter.../twidere/src/main/kotlin/org/mariotaku/twidere/activity/SignInActivity.kt

1080 lines
46 KiB
Kotlin
Raw Normal View History

2016-07-07 09:39:32 +02:00
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@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 org.mariotaku.twidere.activity
2016-12-03 06:48:40 +01:00
import android.accounts.Account
2016-12-02 05:36:50 +01:00
import android.accounts.AccountAuthenticatorResponse
import android.accounts.AccountManager
2016-07-07 09:39:32 +02:00
import android.app.Activity
import android.app.Dialog
2017-01-19 12:43:20 +01:00
import android.content.ActivityNotFoundException
2016-07-07 09:39:32 +02:00
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.res.ColorStateList
import android.net.Uri
import android.os.AsyncTask
import android.os.Bundle
2017-01-19 12:43:20 +01:00
import android.support.customtabs.CustomTabsIntent
2016-07-07 09:39:32 +02:00
import android.support.v4.app.DialogFragment
import android.support.v4.content.ContextCompat
import android.support.v4.util.ArraySet
2016-07-07 09:39:32 +02:00
import android.support.v4.view.ViewCompat
import android.support.v7.app.AlertDialog
import android.text.Editable
import android.text.InputType
import android.text.TextUtils
import android.text.TextWatcher
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.View.OnClickListener
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
2016-12-03 06:48:40 +01:00
import com.bluelinelabs.logansquare.LoganSquare
2016-07-07 09:39:32 +02:00
import com.rengwuxian.materialedittext.MaterialEditText
import kotlinx.android.synthetic.main.activity_sign_in.*
2017-01-19 12:43:20 +01:00
import org.mariotaku.chameleon.Chameleon
import org.mariotaku.chameleon.ChameleonUtils
import org.mariotaku.kpreferences.get
2017-01-02 09:33:27 +01:00
import org.mariotaku.ktextension.*
2016-07-07 09:39:32 +02:00
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.TwitterOAuth
import org.mariotaku.microblog.library.twitter.auth.BasicAuthorization
import org.mariotaku.microblog.library.twitter.auth.EmptyAuthorization
import org.mariotaku.microblog.library.twitter.model.Paging
import org.mariotaku.microblog.library.twitter.model.User
import org.mariotaku.restfu.http.Endpoint
import org.mariotaku.restfu.oauth.OAuthAuthorization
import org.mariotaku.restfu.oauth.OAuthToken
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.activity.iface.APIEditorActivity
2016-12-03 06:48:40 +01:00
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_API_CONFIG
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_CREDENTIALS_TYPE
2017-01-19 12:43:20 +01:00
import org.mariotaku.twidere.constant.chromeCustomTabKey
import org.mariotaku.twidere.constant.defaultAPIConfigKey
import org.mariotaku.twidere.constant.randomizeAccountNameKey
2016-12-29 06:50:18 +01:00
import org.mariotaku.twidere.extension.model.getColor
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
2016-12-15 06:11:32 +01:00
import org.mariotaku.twidere.extension.model.official
2016-07-07 09:39:32 +02:00
import org.mariotaku.twidere.fragment.BaseDialogFragment
import org.mariotaku.twidere.fragment.ProgressDialogFragment
import org.mariotaku.twidere.model.CustomAPIConfig
2016-12-03 06:48:40 +01:00
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.SingleResponse
import org.mariotaku.twidere.model.UserKey
2016-12-15 06:11:32 +01:00
import org.mariotaku.twidere.model.account.AccountExtras
2016-12-03 06:48:40 +01:00
import org.mariotaku.twidere.model.account.StatusNetAccountExtras
import org.mariotaku.twidere.model.account.TwitterAccountExtras
import org.mariotaku.twidere.model.account.cred.BasicCredentials
import org.mariotaku.twidere.model.account.cred.Credentials
import org.mariotaku.twidere.model.account.cred.EmptyCredentials
import org.mariotaku.twidere.model.account.cred.OAuthCredentials
2016-12-15 06:11:32 +01:00
import org.mariotaku.twidere.model.analyzer.SignIn
2016-12-04 04:58:03 +01:00
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.model.util.ParcelableUserUtils
import org.mariotaku.twidere.model.util.UserKeyUtils
2016-07-07 09:39:32 +02:00
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.OAuthPasswordAuthenticator.*
import org.mariotaku.twidere.util.view.ConsumerKeySecretValidator
2017-01-07 17:13:11 +01:00
import java.io.IOException
2016-07-07 09:39:32 +02:00
import java.lang.ref.WeakReference
import java.util.*
2016-07-07 09:39:32 +02:00
2016-12-02 05:36:50 +01:00
2016-07-07 09:39:32 +02:00
class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
private lateinit var apiConfig: CustomAPIConfig
2016-07-07 09:39:32 +02:00
private var apiChangeTimestamp: Long = 0
private var signInTask: AbstractSignInTask? = null
2016-12-02 05:36:50 +01:00
private var accountAuthenticatorResponse: AccountAuthenticatorResponse? = null
private var accountAuthenticatorResult: Bundle? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
accountAuthenticatorResponse = intent.getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE)
accountAuthenticatorResponse?.onRequestContinued()
setContentView(R.layout.activity_sign_in)
if (savedInstanceState != null) {
apiConfig = savedInstanceState.getParcelable(EXTRA_API_CONFIG)
2016-12-02 05:36:50 +01:00
apiChangeTimestamp = savedInstanceState.getLong(EXTRA_API_LAST_CHANGE)
} else {
apiConfig = kPreferences[defaultAPIConfigKey]
2016-12-02 05:36:50 +01:00
}
val isTwipOMode = apiConfig.credentialsType == Credentials.Type.EMPTY
2016-12-02 05:36:50 +01:00
usernamePasswordContainer.visibility = if (isTwipOMode) View.GONE else View.VISIBLE
editUsername.addTextChangedListener(this)
editPassword.addTextChangedListener(this)
2016-07-07 09:39:32 +02:00
2016-12-02 05:36:50 +01:00
signIn.setOnClickListener(this)
signUp.setOnClickListener(this)
passwordSignIn.setOnClickListener(this)
val color = ColorStateList.valueOf(ContextCompat.getColor(this,
R.color.material_light_green))
ViewCompat.setBackgroundTintList(signIn, color)
val consumerKey = preferences.getString(KEY_CONSUMER_KEY, null)
val consumerSecret = preferences.getString(KEY_CONSUMER_SECRET, null)
if (BuildConfig.SHOW_CUSTOM_TOKEN_DIALOG && savedInstanceState == null &&
!preferences.getBoolean(KEY_CONSUMER_KEY_SECRET_SET, false) &&
!Utils.isCustomConsumerKeySecret(consumerKey, consumerSecret)) {
val df = SetConsumerKeySecretDialogFragment()
df.isCancelable = false
df.show(supportFragmentManager, "set_consumer_key_secret")
}
updateSignInType()
setSignInButton()
2016-07-07 09:39:32 +02:00
}
2016-12-02 05:36:50 +01:00
override fun onDestroy() {
loaderManager.destroyLoader(0)
super.onDestroy()
}
2016-07-07 09:39:32 +02:00
2016-12-02 05:36:50 +01:00
override fun onCreateOptionsMenu(menu: Menu): Boolean {
2016-12-29 06:50:18 +01:00
super.onCreateOptionsMenu(menu)
2016-12-02 05:36:50 +01:00
menuInflater.inflate(R.menu.menu_sign_in, menu)
return true
2016-07-07 09:39:32 +02:00
}
2016-12-02 05:36:50 +01:00
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
2016-07-07 09:39:32 +02:00
when (requestCode) {
REQUEST_EDIT_API -> {
if (resultCode == Activity.RESULT_OK) {
apiConfig = data!!.getParcelableExtra(EXTRA_API_CONFIG)
2016-07-07 09:39:32 +02:00
updateSignInType()
}
setSignInButton()
invalidateOptionsMenu()
}
REQUEST_BROWSER_SIGN_IN -> {
if (resultCode == Activity.RESULT_OK && data != null) {
doBrowserLogin(data)
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}
2016-12-02 05:36:50 +01:00
override fun finish() {
accountAuthenticatorResponse?.let { response ->
// send the result bundle back if set, otherwise send an error.
if (accountAuthenticatorResult != null) {
response.onResult(accountAuthenticatorResult)
} else {
response.onError(AccountManager.ERROR_CODE_CANCELED, "canceled")
}
accountAuthenticatorResponse = null
}
super.finish()
}
override fun afterTextChanged(s: Editable) {
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
2016-07-07 09:39:32 +02:00
internal fun updateSignInType() {
when (apiConfig.credentialsType) {
2016-12-03 06:48:40 +01:00
Credentials.Type.XAUTH, Credentials.Type.BASIC -> {
2016-07-07 09:39:32 +02:00
usernamePasswordContainer.visibility = View.VISIBLE
}
2016-12-03 06:48:40 +01:00
Credentials.Type.EMPTY -> {
2016-07-07 09:39:32 +02:00
usernamePasswordContainer.visibility = View.GONE
}
else -> {
usernamePasswordContainer.visibility = View.GONE
}
}
}
override fun onClick(v: View) {
when (v) {
signUp -> {
2017-01-19 12:43:20 +01:00
val signUpUrl = apiConfig.signUpUrl ?: return
val uri = Uri.parse(signUpUrl)
if (preferences[chromeCustomTabKey]) {
val builder = CustomTabsIntent.Builder()
builder.setToolbarColor(overrideTheme.colorToolbar)
val intent = builder.build()
try {
intent.launchUrl(this, uri)
} catch (e: ActivityNotFoundException) {
// Ignore
}
} else {
val intent = Intent(Intent.ACTION_VIEW, uri)
try {
startActivity(intent)
} catch (e: ActivityNotFoundException) {
// Ignore
}
}
2016-07-07 09:39:32 +02:00
}
signIn -> {
if (usernamePasswordContainer.visibility != View.VISIBLE) {
editUsername.text = null
editPassword.text = null
}
doLogin()
}
passwordSignIn -> {
2017-01-19 12:43:20 +01:00
executeAfterFragmentResumed { fragment ->
2016-07-07 09:39:32 +02:00
val df = PasswordSignInDialogFragment()
2017-01-19 12:43:20 +01:00
df.show(fragment.supportFragmentManager, "password_sign_in")
2016-07-07 09:39:32 +02:00
}
}
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
val accountKeys = DataStoreUtils.getActivatedAccountKeys(this)
2016-12-03 06:48:40 +01:00
if (accountKeys.isNotEmpty()) {
2016-07-07 09:39:32 +02:00
onBackPressed()
}
}
R.id.settings -> {
if (signInTask != null && signInTask!!.status == AsyncTask.Status.RUNNING)
return false
val intent = Intent(this, SettingsActivity::class.java)
startActivity(intent)
}
R.id.edit_api -> {
if (signInTask != null && signInTask!!.status == AsyncTask.Status.RUNNING)
return false
setDefaultAPI()
val intent = Intent(this, APIEditorActivity::class.java)
intent.putExtra(EXTRA_API_CONFIG, apiConfig)
2016-07-07 09:39:32 +02:00
startActivityForResult(intent, REQUEST_EDIT_API)
}
}
return super.onOptionsItemSelected(item)
}
internal fun openBrowserLogin(): Boolean {
if (apiConfig.credentialsType != Credentials.Type.OAUTH || signInTask != null && signInTask!!.status == AsyncTask.Status.RUNNING)
2016-07-07 09:39:32 +02:00
return true
val intent = Intent(this, BrowserSignInActivity::class.java)
intent.putExtra(EXTRA_API_CONFIG, apiConfig)
2016-07-07 09:39:32 +02:00
startActivityForResult(intent, REQUEST_BROWSER_SIGN_IN)
return false
}
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
super.onPrepareOptionsMenu(menu)
2016-07-07 09:39:32 +02:00
val itemBrowser = menu.findItem(R.id.open_in_browser)
if (itemBrowser != null) {
val is_oauth = apiConfig.credentialsType == Credentials.Type.OAUTH
2016-07-07 09:39:32 +02:00
itemBrowser.isVisible = is_oauth
itemBrowser.isEnabled = is_oauth
}
return true
}
public override fun onSaveInstanceState(outState: Bundle) {
outState.putParcelable(EXTRA_API_CONFIG, apiConfig)
2016-07-07 09:39:32 +02:00
outState.putLong(EXTRA_API_LAST_CHANGE, apiChangeTimestamp)
super.onSaveInstanceState(outState)
}
2016-12-02 05:36:50 +01:00
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
2016-07-07 09:39:32 +02:00
setSignInButton()
}
internal fun doLogin() {
if (signInTask != null && signInTask!!.status == AsyncTask.Status.RUNNING) {
signInTask!!.cancel(true)
}
2017-01-07 17:13:11 +01:00
if (apiConfig.credentialsType == Credentials.Type.OAUTH) {
2016-07-07 09:39:32 +02:00
openBrowserLogin()
return
}
2016-07-07 09:39:32 +02:00
val username = editUsername.text.toString()
val password = editPassword.text.toString()
2017-01-07 17:13:11 +01:00
signInTask = SignInTask(this, username, password, apiConfig)
2016-07-07 09:39:32 +02:00
AsyncTaskUtils.executeTask<AbstractSignInTask, Any>(signInTask)
}
private fun doBrowserLogin(intent: Intent?) {
if (intent == null) return
if (signInTask?.status == AsyncTask.Status.RUNNING) {
signInTask?.cancel(true)
2016-07-07 09:39:32 +02:00
}
val verifier = intent.getStringExtra(EXTRA_OAUTH_VERIFIER)
val requestToken = OAuthToken(intent.getStringExtra(EXTRA_REQUEST_TOKEN),
intent.getStringExtra(EXTRA_REQUEST_TOKEN_SECRET))
2017-01-07 17:13:11 +01:00
signInTask = BrowserSignInTask(this, apiConfig, requestToken, verifier)
2016-07-07 09:39:32 +02:00
AsyncTaskUtils.executeTask<AbstractSignInTask, Any>(signInTask)
}
private fun setDefaultAPI() {
val apiLastChange = preferences.getLong(KEY_API_LAST_CHANGE, apiChangeTimestamp)
val defaultApiChanged = apiLastChange != apiChangeTimestamp
val apiUrlFormat = Utils.getNonEmptyString(preferences, KEY_API_URL_FORMAT, DEFAULT_TWITTER_API_URL_FORMAT)
val authType = preferences.getString(KEY_CREDENTIALS_TYPE, Credentials.Type.OAUTH)
2016-07-07 09:39:32 +02:00
val sameOAuthSigningUrl = preferences.getBoolean(KEY_SAME_OAUTH_SIGNING_URL, false)
val noVersionSuffix = preferences.getBoolean(KEY_NO_VERSION_SUFFIX, false)
val consumerKey = Utils.getNonEmptyString(preferences, KEY_CONSUMER_KEY, TWITTER_CONSUMER_KEY)
val consumerSecret = Utils.getNonEmptyString(preferences, KEY_CONSUMER_SECRET, TWITTER_CONSUMER_SECRET)
if (TextUtils.isEmpty(apiConfig.apiUrlFormat) || defaultApiChanged) {
apiConfig.apiUrlFormat = apiUrlFormat
2016-07-07 09:39:32 +02:00
}
if (defaultApiChanged) {
apiConfig.credentialsType = authType
2016-07-07 09:39:32 +02:00
}
if (defaultApiChanged) {
apiConfig.isSameOAuthUrl = sameOAuthSigningUrl
2016-07-07 09:39:32 +02:00
}
if (defaultApiChanged) {
apiConfig.isNoVersionSuffix = noVersionSuffix
2016-07-07 09:39:32 +02:00
}
if (TextUtils.isEmpty(apiConfig.consumerKey) || defaultApiChanged) {
apiConfig.consumerKey = consumerKey
2016-07-07 09:39:32 +02:00
}
if (TextUtils.isEmpty(apiConfig.consumerSecret) || defaultApiChanged) {
apiConfig.consumerSecret = consumerSecret
2016-07-07 09:39:32 +02:00
}
if (defaultApiChanged) {
apiChangeTimestamp = apiLastChange
}
}
private fun setSignInButton() {
when (apiConfig.credentialsType) {
2016-12-03 06:48:40 +01:00
Credentials.Type.XAUTH, Credentials.Type.BASIC -> {
2016-07-07 09:39:32 +02:00
passwordSignIn.visibility = View.GONE
2016-12-03 06:48:40 +01:00
signIn.isEnabled = editPassword.text.isNotEmpty() && editUsername.text.isNotEmpty()
2016-07-07 09:39:32 +02:00
}
2016-12-03 06:48:40 +01:00
Credentials.Type.OAUTH -> {
2016-07-07 09:39:32 +02:00
passwordSignIn.visibility = View.VISIBLE
signIn.isEnabled = true
}
else -> {
passwordSignIn.visibility = View.GONE
signIn.isEnabled = true
}
}
2017-01-19 12:43:20 +01:00
signUp.visibility = if (apiConfig.signUpUrl != null) {
View.VISIBLE
} else {
View.GONE
}
passwordSignIn.visibility = if (apiConfig.type == null || apiConfig.type == AccountType.TWITTER) {
View.VISIBLE
} else {
View.GONE
}
2016-07-07 09:39:32 +02:00
}
2016-12-03 06:48:40 +01:00
internal fun onSignInResult(result: SignInResponse) {
val am = AccountManager.get(this)
2016-07-07 09:39:32 +02:00
setSignInButton()
2016-12-03 06:48:40 +01:00
if (result.alreadyLoggedIn) {
result.updateAccount(am)
Toast.makeText(this, R.string.error_already_logged_in, Toast.LENGTH_SHORT).show()
} else {
result.addAccount(am, preferences[randomizeAccountNameKey])
2016-12-15 13:15:58 +01:00
Analyzer.log(SignIn(true, accountType = result.accountType.first, credentialsType = apiConfig.credentialsType,
2016-12-15 06:11:32 +01:00
officialKey = result.accountType.second?.official ?: false))
2016-12-17 05:10:24 +01:00
finishSignIn()
}
}
private fun finishSignIn() {
if (accountAuthenticatorResponse != null) {
accountAuthenticatorResult = Bundle {
this[AccountManager.KEY_BOOLEAN_RESULT] = true
}
} else {
val intent = Intent(this, HomeActivity::class.java)
2017-01-07 17:13:11 +01:00
//TODO refresh timelines
2016-12-17 05:10:24 +01:00
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
startActivity(intent)
2016-12-03 06:48:40 +01:00
}
2016-12-17 05:10:24 +01:00
finish()
2016-07-07 09:39:32 +02:00
}
2016-12-03 06:48:40 +01:00
internal fun onSignInError(exception: Exception) {
if (BuildConfig.DEBUG) {
Log.w(LOGTAG, exception)
}
2016-12-15 06:11:32 +01:00
var errorReason: String? = null
2016-12-03 06:48:40 +01:00
if (exception is AuthenticityTokenException) {
Toast.makeText(this, R.string.wrong_api_key, Toast.LENGTH_SHORT).show()
2016-12-15 06:11:32 +01:00
errorReason = "wrong_api_key"
2016-12-03 06:48:40 +01:00
} else if (exception is WrongUserPassException) {
Toast.makeText(this, R.string.wrong_username_password, Toast.LENGTH_SHORT).show()
2016-12-15 06:11:32 +01:00
errorReason = "wrong_username_password"
2016-12-03 06:48:40 +01:00
} else if (exception is SignInTask.WrongBasicCredentialException) {
Toast.makeText(this, R.string.wrong_username_password, Toast.LENGTH_SHORT).show()
2016-12-15 06:11:32 +01:00
errorReason = "wrong_username_password"
2016-12-03 06:48:40 +01:00
} else if (exception is SignInTask.WrongAPIURLFormatException) {
Toast.makeText(this, R.string.wrong_api_key, Toast.LENGTH_SHORT).show()
2016-12-15 06:11:32 +01:00
errorReason = "wrong_api_key"
2016-12-03 06:48:40 +01:00
} else if (exception is LoginVerificationException) {
Toast.makeText(this, R.string.login_verification_failed, Toast.LENGTH_SHORT).show()
2016-12-15 06:11:32 +01:00
errorReason = "login_verification_failed"
2016-12-03 06:48:40 +01:00
} else if (exception is AuthenticationException) {
Utils.showErrorMessage(this, getString(R.string.action_signing_in), exception.cause, true)
} else {
Utils.showErrorMessage(this, getString(R.string.action_signing_in), exception, true)
}
2017-01-07 17:13:11 +01:00
Analyzer.log(SignIn(false, credentialsType = apiConfig.credentialsType,
errorReason = errorReason, accountType = apiConfig.type))
2016-12-03 06:48:40 +01:00
}
2016-07-07 09:39:32 +02:00
internal fun dismissDialogFragment(tag: String) {
executeAfterFragmentResumed {
val fm = supportFragmentManager
val f = fm.findFragmentByTag(tag)
if (f is DialogFragment) {
f.dismiss()
}
Unit
}
}
internal fun onSignInStart() {
showSignInProgressDialog()
}
internal fun showSignInProgressDialog() {
executeAfterFragmentResumed {
2016-09-01 04:43:59 +02:00
if (isFinishing) return@executeAfterFragmentResumed
2016-07-07 09:39:32 +02:00
val fm = supportFragmentManager
val ft = fm.beginTransaction()
val fragment = ProgressDialogFragment()
fragment.isCancelable = false
fragment.show(ft, FRAGMENT_TAG_SIGN_IN_PROGRESS)
}
}
internal fun setUsernamePassword(username: String, password: String) {
editUsername.setText(username)
editPassword.setText(password)
}
2016-12-03 06:48:40 +01:00
internal abstract class AbstractSignInTask(activity: SignInActivity) : AsyncTask<Any, Runnable, SingleResponse<SignInResponse>>() {
2016-07-07 09:39:32 +02:00
protected val activityRef: WeakReference<SignInActivity>
init {
this.activityRef = WeakReference(activity)
}
2016-12-03 06:48:40 +01:00
override final fun doInBackground(vararg args: Any?): SingleResponse<SignInResponse> {
try {
return SingleResponse.getInstance(performLogin())
} catch (e: Exception) {
return SingleResponse.getInstance(e)
}
}
abstract fun performLogin(): SignInResponse
override fun onPostExecute(result: SingleResponse<SignInResponse>) {
2016-07-07 09:39:32 +02:00
val activity = activityRef.get()
2016-12-15 06:49:18 +01:00
activity?.dismissDialogFragment(FRAGMENT_TAG_SIGN_IN_PROGRESS)
2016-12-03 06:48:40 +01:00
if (result.hasData()) {
activity?.onSignInResult(result.data!!)
} else {
activity?.onSignInError(result.exception!!)
}
2016-07-07 09:39:32 +02:00
}
override fun onPreExecute() {
val activity = activityRef.get()
activity?.onSignInStart()
}
override fun onProgressUpdate(vararg values: Runnable) {
for (value in values) {
value.run()
}
}
@Throws(MicroBlogException::class)
internal fun analyseUserProfileColor(user: User?): Int {
if (user == null) throw MicroBlogException("Unable to get user info")
2016-12-09 14:20:02 +01:00
return ParcelableUserUtils.parseColor(user.profileLinkColor)
2016-07-07 09:39:32 +02:00
}
}
/**
* Created by mariotaku on 16/7/7.
*/
internal class BrowserSignInTask(
context: SignInActivity,
2017-01-07 17:13:11 +01:00
private val apiConfig: CustomAPIConfig,
2016-07-07 09:39:32 +02:00
private val requestToken: OAuthToken,
2017-01-07 17:13:11 +01:00
private val oauthVerifier: String?
2016-07-07 09:39:32 +02:00
) : AbstractSignInTask(context) {
private val context: Context
init {
this.context = context
}
2016-12-03 06:48:40 +01:00
@Throws(Exception::class)
override fun performLogin(): SignInResponse {
2017-01-07 17:13:11 +01:00
val versionSuffix = if (apiConfig.isNoVersionSuffix) null else "1.1"
var endpoint = MicroBlogAPIFactory.getOAuthSignInEndpoint(apiConfig.apiUrlFormat,
apiConfig.isSameOAuthUrl)
2016-12-08 16:45:07 +01:00
val oauth = newMicroBlogInstance(context, endpoint = endpoint,
2017-01-07 17:13:11 +01:00
auth = OAuthAuthorization(apiConfig.consumerKey, apiConfig.consumerSecret),
2016-12-08 16:45:07 +01:00
cls = TwitterOAuth::class.java)
2016-12-03 06:48:40 +01:00
val accessToken: OAuthToken
if (oauthVerifier != null) {
accessToken = oauth.getAccessToken(requestToken, oauthVerifier)
} else {
accessToken = oauth.getAccessToken(requestToken)
}
2017-01-07 17:13:11 +01:00
val auth = OAuthAuthorization(apiConfig.consumerKey,
apiConfig.consumerSecret, accessToken)
endpoint = MicroBlogAPIFactory.getOAuthEndpoint(apiConfig.apiUrlFormat, "api", versionSuffix,
apiConfig.isSameOAuthUrl)
2016-12-08 16:45:07 +01:00
val twitter = newMicroBlogInstance(context, endpoint = endpoint, auth = auth,
cls = MicroBlog::class.java)
2016-12-03 06:48:40 +01:00
val apiUser = twitter.verifyCredentials()
var color = analyseUserProfileColor(apiUser)
2017-01-07 17:13:11 +01:00
val accountType = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type)
2016-12-03 06:48:40 +01:00
val userId = apiUser.id!!
val accountKey = UserKey(userId, UserKeyUtils.getUserHost(apiUser))
val user = ParcelableUserUtils.fromUser(apiUser, accountKey)
2016-12-15 06:11:32 +01:00
val am = AccountManager.get(context)
val account = AccountUtils.findByAccountKey(am, accountKey)
2016-12-03 06:48:40 +01:00
if (account != null) {
2016-12-15 06:11:32 +01:00
color = account.getColor(am)
2016-07-07 09:39:32 +02:00
}
2016-12-03 06:48:40 +01:00
val credentials = OAuthCredentials()
2017-01-07 17:13:11 +01:00
credentials.api_url_format = apiConfig.apiUrlFormat
credentials.no_version_suffix = apiConfig.isNoVersionSuffix
2016-12-03 06:48:40 +01:00
2017-01-07 17:13:11 +01:00
credentials.same_oauth_signing_url = apiConfig.isSameOAuthUrl
2016-12-03 06:48:40 +01:00
2017-01-07 17:13:11 +01:00
credentials.consumer_key = apiConfig.consumerKey
credentials.consumer_secret = apiConfig.consumerSecret
2016-12-03 06:48:40 +01:00
credentials.access_token = accessToken.oauthToken
credentials.access_token_secret = accessToken.oauthTokenSecret
2016-07-07 09:39:32 +02:00
2016-12-03 06:48:40 +01:00
return SignInResponse(account != null, Credentials.Type.OAUTH, credentials, user, color,
accountType)
2016-07-07 09:39:32 +02:00
}
}
/**
* Created by mariotaku on 16/7/7.
*/
class InputLoginVerificationDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener, DialogInterface.OnShowListener {
private var callback: SignInTask.InputLoginVerificationCallback? = null
2016-07-12 03:22:33 +02:00
var challengeType: String? = null
2016-07-07 09:39:32 +02:00
internal fun setCallback(callback: SignInTask.InputLoginVerificationCallback) {
this.callback = callback
}
override fun onCancel(dialog: DialogInterface?) {
callback!!.challengeResponse = null
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.login_verification)
builder.setView(R.layout.dialog_login_verification_code)
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, this)
val dialog = builder.create()
dialog.setOnShowListener(this)
return dialog
}
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val alertDialog = dialog as AlertDialog
val editVerification = (alertDialog.findViewById(R.id.edit_verification_code) as EditText?)!!
callback!!.challengeResponse = ParseUtils.parseString(editVerification.text)
}
DialogInterface.BUTTON_NEGATIVE -> {
callback!!.challengeResponse = null
}
}
}
override fun onShow(dialog: DialogInterface) {
val alertDialog = dialog as AlertDialog
val verificationHint = alertDialog.findViewById(R.id.verification_hint) as TextView?
val editVerification = alertDialog.findViewById(R.id.edit_verification_code) as EditText?
if (verificationHint == null || editVerification == null) return
2016-07-12 03:22:33 +02:00
when {
"Push".equals(challengeType, ignoreCase = true) -> {
verificationHint.setText(R.string.login_verification_push_hint)
editVerification.visibility = View.GONE
}
"RetypePhoneNumber".equals(challengeType, ignoreCase = true) -> {
verificationHint.setText(R.string.login_challenge_retype_phone_hint)
editVerification.inputType = InputType.TYPE_CLASS_PHONE
editVerification.visibility = View.VISIBLE
}
"RetypeEmail".equals(challengeType, ignoreCase = true) -> {
verificationHint.setText(R.string.login_challenge_retype_email_hint)
editVerification.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
editVerification.visibility = View.VISIBLE
}
"Sms".equals(challengeType, ignoreCase = true) -> {
verificationHint.setText(R.string.login_verification_pin_hint)
editVerification.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
editVerification.visibility = View.VISIBLE
}
else -> {
verificationHint.text = getString(R.string.unsupported_login_verification_type_name,
challengeType)
editVerification.visibility = View.VISIBLE
}
2016-07-07 09:39:32 +02:00
}
}
}
class PasswordSignInDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context)
builder.setView(R.layout.dialog_password_sign_in)
builder.setPositiveButton(R.string.sign_in) { dialog, which ->
val alertDialog = dialog as AlertDialog
val editUsername = alertDialog.findViewById(R.id.username) as EditText?
val editPassword = alertDialog.findViewById(R.id.password) as EditText?
assert(editUsername != null && editPassword != null)
val activity = activity as SignInActivity
activity.setUsernamePassword(editUsername!!.text.toString(),
editPassword!!.text.toString())
activity.doLogin()
}
builder.setNegativeButton(android.R.string.cancel, null)
val alertDialog = builder.create()
alertDialog.setOnShowListener { dialog ->
val materialDialog = dialog as AlertDialog
val editUsername = materialDialog.findViewById(R.id.username) as EditText?
val editPassword = materialDialog.findViewById(R.id.password) as EditText?
assert(editUsername != null && editPassword != null)
val textWatcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
val button = materialDialog.getButton(DialogInterface.BUTTON_POSITIVE) ?: return
button.isEnabled = editUsername!!.length() > 0 && editPassword!!.length() > 0
}
override fun afterTextChanged(s: Editable) {
}
}
editUsername!!.addTextChangedListener(textWatcher)
editPassword!!.addTextChangedListener(textWatcher)
}
return alertDialog
}
}
class SetConsumerKeySecretDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(activity)
builder.setView(R.layout.dialog_set_consumer_key_secret)
builder.setPositiveButton(android.R.string.ok) { dialog, which ->
2016-08-20 03:59:48 +02:00
val editConsumerKey = (dialog as Dialog).findViewById(R.id.editConsumerKey) as EditText
val editConsumerSecret = dialog.findViewById(R.id.editConsumerSecret) as EditText
val apiConfig = kPreferences[defaultAPIConfigKey]
apiConfig.consumerKey = editConsumerKey.text.toString()
apiConfig.consumerSecret = editConsumerSecret.text.toString()
kPreferences[defaultAPIConfigKey] = apiConfig
2016-07-07 09:39:32 +02:00
}
val dialog = builder.create()
dialog.setOnShowListener(DialogInterface.OnShowListener { dialog ->
val activity = activity ?: return@OnShowListener
2016-08-20 03:59:48 +02:00
val editConsumerKey = (dialog as Dialog).findViewById(R.id.editConsumerKey) as MaterialEditText
val editConsumerSecret = dialog.findViewById(R.id.editConsumerSecret) as MaterialEditText
2016-07-07 09:39:32 +02:00
editConsumerKey.addValidator(ConsumerKeySecretValidator(getString(R.string.invalid_consumer_key)))
editConsumerSecret.addValidator(ConsumerKeySecretValidator(getString(R.string.invalid_consumer_secret)))
val apiConfig = kPreferences[defaultAPIConfigKey]
editConsumerKey.setText(apiConfig.consumerKey)
editConsumerSecret.setText(apiConfig.consumerSecret)
2016-07-07 09:39:32 +02:00
})
return dialog
}
}
internal data class SignInResponse(
val alreadyLoggedIn: Boolean,
2016-12-08 08:33:13 +01:00
@Credentials.Type val credsType: String = Credentials.Type.EMPTY,
2016-12-03 06:48:40 +01:00
val credentials: Credentials,
val user: ParcelableUser,
2016-07-07 09:39:32 +02:00
val color: Int = 0,
2016-12-15 06:11:32 +01:00
val accountType: Pair<String, AccountExtras?>
2016-07-07 09:39:32 +02:00
) {
private fun writeAccountInfo(action: (k: String, v: String?) -> Unit) {
action(ACCOUNT_USER_DATA_KEY, user.key.toString())
action(ACCOUNT_USER_DATA_TYPE, accountType.first)
action(ACCOUNT_USER_DATA_CREDS_TYPE, credsType)
2016-07-07 09:39:32 +02:00
action(ACCOUNT_USER_DATA_ACTIVATED, true.toString())
2017-01-02 09:33:27 +01:00
action(ACCOUNT_USER_DATA_COLOR, toHexColor(color, format = HexColorFormat.RGB))
2016-07-07 09:39:32 +02:00
action(ACCOUNT_USER_DATA_USER, LoganSquare.serialize(user))
2016-12-15 06:11:32 +01:00
action(ACCOUNT_USER_DATA_EXTRAS, accountType.second?.convert { LoganSquare.serialize(it) })
2016-12-08 08:33:13 +01:00
}
2016-07-07 09:39:32 +02:00
2016-12-08 08:33:13 +01:00
private fun writeAuthToken(am: AccountManager, account: Account) {
val authToken = LoganSquare.serialize(credentials)
am.setAuthToken(account, ACCOUNT_AUTH_TOKEN_TYPE, authToken)
2016-12-03 06:48:40 +01:00
}
2016-07-07 09:39:32 +02:00
2016-12-03 06:48:40 +01:00
fun updateAccount(am: AccountManager) {
val account = AccountUtils.findByAccountKey(am, user.key) ?: return
writeAccountInfo { k, v ->
2016-12-08 08:33:13 +01:00
am.setUserData(account, k, v)
}
writeAuthToken(am, account)
2016-12-03 06:48:40 +01:00
}
2016-07-07 09:39:32 +02:00
fun addAccount(am: AccountManager, randomizeAccountName: Boolean): Account {
var accountName: String
if (randomizeAccountName) {
val usedNames = ArraySet<String>()
AccountUtils.getAccounts(am).mapTo(usedNames, Account::name)
do {
accountName = UUID.randomUUID().toString()
} while (usedNames.contains(accountName))
} else {
accountName = generateAccountName(user.screen_name, user.key.host)
}
val account = Account(accountName, ACCOUNT_TYPE)
val accountPosition = AccountUtils.getAccounts(am).size
// Don't add UserData in this method, see http://stackoverflow.com/a/29776224/859190
am.addAccountExplicitly(account, null, null)
writeAccountInfo { k, v ->
am.setUserData(account, k, v)
2016-12-08 08:33:13 +01:00
}
am.setUserData(account, ACCOUNT_USER_DATA_POSITION, accountPosition.toString())
writeAuthToken(am, account)
2016-12-08 08:33:13 +01:00
return account
2016-07-07 09:39:32 +02:00
}
2016-07-07 09:39:32 +02:00
}
2016-12-03 06:48:40 +01:00
internal class SignInTask(
activity: SignInActivity,
private val username: String,
private val password: String,
2017-01-07 17:13:11 +01:00
private val apiConfig: CustomAPIConfig
2016-12-03 06:48:40 +01:00
) : AbstractSignInTask(activity) {
2017-01-07 17:13:11 +01:00
private val verificationCallback = InputLoginVerificationCallback()
private val userAgent = UserAgentUtils.getDefaultUserAgentString(activity)
private val apiUrlFormat = apiConfig.apiUrlFormat ?: DEFAULT_TWITTER_API_URL_FORMAT
2016-07-07 09:39:32 +02:00
2016-12-03 06:48:40 +01:00
@Throws(Exception::class)
override fun performLogin(): SignInResponse {
2017-01-07 17:13:11 +01:00
when (apiConfig.credentialsType) {
2016-12-03 06:48:40 +01:00
Credentials.Type.OAUTH -> return authOAuth()
Credentials.Type.XAUTH -> return authxAuth()
Credentials.Type.BASIC -> return authBasic()
Credentials.Type.EMPTY -> return authTwipOMode()
2016-07-07 09:39:32 +02:00
}
2016-12-03 06:48:40 +01:00
return authOAuth()
2016-07-07 09:39:32 +02:00
}
@Throws(OAuthPasswordAuthenticator.AuthenticationException::class, MicroBlogException::class)
private fun authOAuth(): SignInResponse {
2016-12-03 06:48:40 +01:00
val activity = activityRef.get() ?: throw InterruptedException()
2016-07-07 09:39:32 +02:00
val endpoint = MicroBlogAPIFactory.getOAuthSignInEndpoint(apiUrlFormat,
2017-01-07 17:13:11 +01:00
apiConfig.isSameOAuthUrl)
val auth = OAuthAuthorization(apiConfig.consumerKey,
apiConfig.consumerSecret)
2016-12-08 16:45:07 +01:00
val oauth = newMicroBlogInstance(activity, endpoint = endpoint, auth = auth,
cls = TwitterOAuth::class.java)
2016-07-07 09:39:32 +02:00
val authenticator = OAuthPasswordAuthenticator(oauth,
verificationCallback, userAgent)
val accessToken = authenticator.getOAuthAccessToken(username, password)
2016-12-03 06:48:40 +01:00
val userId = accessToken.userId!!
2016-07-07 09:39:32 +02:00
return getOAuthSignInResponse(activity, accessToken, userId,
2016-12-03 06:48:40 +01:00
Credentials.Type.OAUTH)
2016-07-07 09:39:32 +02:00
}
@Throws(MicroBlogException::class)
private fun authxAuth(): SignInResponse {
2016-12-03 06:48:40 +01:00
val activity = activityRef.get() ?: throw InterruptedException()
2016-07-07 09:39:32 +02:00
var endpoint = MicroBlogAPIFactory.getOAuthSignInEndpoint(apiUrlFormat,
2017-01-07 17:13:11 +01:00
apiConfig.isSameOAuthUrl)
var auth = OAuthAuthorization(apiConfig.consumerKey,
apiConfig.consumerSecret)
2016-12-08 16:45:07 +01:00
val oauth = newMicroBlogInstance(activity, endpoint = endpoint, auth = auth,
cls = TwitterOAuth::class.java)
2016-07-07 09:39:32 +02:00
val accessToken = oauth.getAccessToken(username, password)
var userId: String? = accessToken.userId
if (userId == null) {
// Trying to fix up userId if accessToken doesn't contain one.
2017-01-07 17:13:11 +01:00
auth = OAuthAuthorization(apiConfig.consumerKey,
apiConfig.consumerSecret, accessToken)
endpoint = MicroBlogAPIFactory.getOAuthRestEndpoint(apiUrlFormat, apiConfig.isSameOAuthUrl,
apiConfig.isNoVersionSuffix)
2016-12-08 16:45:07 +01:00
val microBlog = newMicroBlogInstance(activity, endpoint = endpoint, auth = auth,
cls = MicroBlog::class.java)
2016-07-07 09:39:32 +02:00
userId = microBlog.verifyCredentials().id
}
2016-12-03 06:48:40 +01:00
return getOAuthSignInResponse(activity, accessToken, userId!!, Credentials.Type.XAUTH)
2016-07-07 09:39:32 +02:00
}
@Throws(MicroBlogException::class, OAuthPasswordAuthenticator.AuthenticationException::class)
private fun authBasic(): SignInResponse {
2016-12-03 06:48:40 +01:00
val activity = activityRef.get() ?: throw InterruptedException()
2017-01-07 17:13:11 +01:00
val versionSuffix = if (apiConfig.isNoVersionSuffix) null else "1.1"
2016-07-07 09:39:32 +02:00
val endpoint = Endpoint(MicroBlogAPIFactory.getApiUrl(apiUrlFormat, "api",
versionSuffix))
val auth = BasicAuthorization(username, password)
2016-12-08 16:45:07 +01:00
val twitter = newMicroBlogInstance(activity, endpoint = endpoint, auth = auth,
cls = MicroBlog::class.java)
2016-12-03 06:48:40 +01:00
val apiUser: User
2016-07-07 09:39:32 +02:00
try {
2016-12-03 06:48:40 +01:00
apiUser = twitter.verifyCredentials()
2016-07-07 09:39:32 +02:00
} catch (e: MicroBlogException) {
if (e.statusCode == 401) {
throw WrongBasicCredentialException()
} else if (e.statusCode == 404) {
throw WrongAPIURLFormatException()
}
throw e
}
2016-12-03 06:48:40 +01:00
val userId = apiUser.id!!
var color = analyseUserProfileColor(apiUser)
2017-01-07 17:13:11 +01:00
val accountType = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type)
2016-12-03 06:48:40 +01:00
val accountKey = UserKey(userId, UserKeyUtils.getUserHost(apiUser))
val user = ParcelableUserUtils.fromUser(apiUser, accountKey)
2016-12-15 06:11:32 +01:00
val am = AccountManager.get(activity)
val account = AccountUtils.findByAccountKey(am, accountKey)
2016-07-07 09:39:32 +02:00
if (account != null) {
2016-12-15 06:11:32 +01:00
color = account.getColor(am)
2016-07-07 09:39:32 +02:00
}
2016-12-03 06:48:40 +01:00
val credentials = BasicCredentials()
credentials.api_url_format = apiUrlFormat
2017-01-07 17:13:11 +01:00
credentials.no_version_suffix = apiConfig.isNoVersionSuffix
2016-12-03 06:48:40 +01:00
credentials.username = username
credentials.password = password
return SignInResponse(account != null, Credentials.Type.BASIC, credentials, user,
color, accountType)
2016-07-07 09:39:32 +02:00
}
@Throws(MicroBlogException::class)
private fun authTwipOMode(): SignInResponse {
2016-12-03 06:48:40 +01:00
val activity = activityRef.get() ?: throw InterruptedException()
2017-01-07 17:13:11 +01:00
val versionSuffix = if (apiConfig.isNoVersionSuffix) null else "1.1"
2016-07-07 09:39:32 +02:00
val endpoint = Endpoint(MicroBlogAPIFactory.getApiUrl(apiUrlFormat, "api",
versionSuffix))
val auth = EmptyAuthorization()
2016-12-08 16:45:07 +01:00
val twitter = newMicroBlogInstance(activity, endpoint = endpoint, auth = auth,
cls = MicroBlog::class.java)
2016-12-03 06:48:40 +01:00
val apiUser = twitter.verifyCredentials()
val userId = apiUser.id!!
var color = analyseUserProfileColor(apiUser)
2017-01-07 17:13:11 +01:00
val accountType = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type)
2016-12-03 06:48:40 +01:00
val accountKey = UserKey(userId, UserKeyUtils.getUserHost(apiUser))
val user = ParcelableUserUtils.fromUser(apiUser, accountKey)
2016-12-15 06:11:32 +01:00
val am = AccountManager.get(activity)
val account = AccountUtils.findByAccountKey(am, accountKey)
2016-07-07 09:39:32 +02:00
if (account != null) {
2016-12-15 06:11:32 +01:00
color = account.getColor(am)
2016-07-07 09:39:32 +02:00
}
2016-12-03 06:48:40 +01:00
val credentials = EmptyCredentials()
credentials.api_url_format = apiUrlFormat
2017-01-07 17:13:11 +01:00
credentials.no_version_suffix = apiConfig.isNoVersionSuffix
2016-12-03 06:48:40 +01:00
return SignInResponse(account != null, Credentials.Type.EMPTY, credentials, user, color,
accountType)
2016-07-07 09:39:32 +02:00
}
@Throws(MicroBlogException::class)
private fun getOAuthSignInResponse(activity: SignInActivity,
accessToken: OAuthToken,
2016-12-03 06:48:40 +01:00
userId: String, @Credentials.Type authType: String): SignInResponse {
2017-01-07 17:13:11 +01:00
val auth = OAuthAuthorization(apiConfig.consumerKey,
apiConfig.consumerSecret, accessToken)
2016-07-07 09:39:32 +02:00
val endpoint = MicroBlogAPIFactory.getOAuthRestEndpoint(apiUrlFormat,
2017-01-07 17:13:11 +01:00
apiConfig.isSameOAuthUrl, apiConfig.isNoVersionSuffix)
2016-12-08 16:45:07 +01:00
val twitter = newMicroBlogInstance(activity, endpoint = endpoint, auth = auth,
cls = MicroBlog::class.java)
2016-12-03 06:48:40 +01:00
val apiUser = twitter.verifyCredentials()
var color = analyseUserProfileColor(apiUser)
2017-01-07 17:13:11 +01:00
val accountType = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type)
2016-12-03 06:48:40 +01:00
val accountKey = UserKey(userId, UserKeyUtils.getUserHost(apiUser))
val user = ParcelableUserUtils.fromUser(apiUser, accountKey)
2016-12-15 06:11:32 +01:00
val am = AccountManager.get(activity)
val account = AccountUtils.findByAccountKey(am, accountKey)
2016-07-07 09:39:32 +02:00
if (account != null) {
2016-12-15 06:11:32 +01:00
color = account.getColor(am)
2016-07-07 09:39:32 +02:00
}
2016-12-03 06:48:40 +01:00
val credentials = OAuthCredentials()
credentials.api_url_format = apiUrlFormat
2017-01-07 17:13:11 +01:00
credentials.no_version_suffix = apiConfig.isNoVersionSuffix
2016-12-03 06:48:40 +01:00
2017-01-07 17:13:11 +01:00
credentials.same_oauth_signing_url = apiConfig.isSameOAuthUrl
2016-12-03 06:48:40 +01:00
2017-01-07 17:13:11 +01:00
credentials.consumer_key = apiConfig.consumerKey
credentials.consumer_secret = apiConfig.consumerSecret
2016-12-03 06:48:40 +01:00
credentials.access_token = accessToken.oauthToken
credentials.access_token_secret = accessToken.oauthTokenSecret
return SignInResponse(account != null, authType, credentials, user, color, accountType)
2016-07-07 09:39:32 +02:00
}
internal class WrongBasicCredentialException : OAuthPasswordAuthenticator.AuthenticationException()
internal class WrongAPIURLFormatException : OAuthPasswordAuthenticator.AuthenticationException()
internal inner class InputLoginVerificationCallback : OAuthPasswordAuthenticator.LoginVerificationCallback {
var isChallengeFinished: Boolean = false
var challengeResponse: String? = null
set(value) {
isChallengeFinished = true
field = value
}
2016-07-14 14:00:27 +02:00
override fun getLoginVerification(challengeType: String): String? {
2016-07-07 09:39:32 +02:00
// Dismiss current progress dialog
publishProgress(Runnable {
2016-12-15 06:49:18 +01:00
activityRef.get()?.dismissDialogFragment(SignInActivity.FRAGMENT_TAG_SIGN_IN_PROGRESS)
2016-07-07 09:39:32 +02:00
})
// Show verification input dialog and wait for user input
publishProgress(Runnable {
val activity = activityRef.get() ?: return@Runnable
activity.executeAfterFragmentResumed { activity ->
val sia = activity as SignInActivity
val df = InputLoginVerificationDialogFragment()
df.isCancelable = false
df.setCallback(this@InputLoginVerificationCallback)
2016-07-12 03:22:33 +02:00
df.challengeType = challengeType
2016-12-15 06:49:18 +01:00
df.show(sia.supportFragmentManager, "login_challenge_$challengeType")
2016-07-07 09:39:32 +02:00
}
})
while (!isChallengeFinished) {
// Wait for 50ms
try {
Thread.sleep(50)
} catch (e: InterruptedException) {
// Ignore
}
}
// Show progress dialog
publishProgress(Runnable {
val activity = activityRef.get() ?: return@Runnable
activity.showSignInProgressDialog()
})
return challengeResponse
}
}
}
companion object {
val FRAGMENT_TAG_SIGN_IN_PROGRESS = "sign_in_progress"
private val TWITTER_SIGNUP_URL = "https://twitter.com/signup"
private val EXTRA_API_LAST_CHANGE = "api_last_change"
private val DEFAULT_TWITTER_API_URL_FORMAT = "https://[DOMAIN.]twitter.com/"
2017-01-07 17:13:11 +01:00
@Throws(IOException::class)
internal fun detectAccountType(twitter: MicroBlog, user: User, type: String?): Pair<String, AccountExtras?> {
when (type) {
AccountType.STATUSNET -> {
// Get StatusNet specific resource
val config = twitter.statusNetConfig
val extras = StatusNetAccountExtras()
val site = config.site
if (site != null) {
extras.textLimit = site.textLimit
}
return Pair(AccountType.STATUSNET, extras)
}
AccountType.TWITTER -> {
val extras = TwitterAccountExtras()
try {
// Get Twitter official only resource
val paging = Paging()
paging.count(1)
twitter.getActivitiesAboutMe(paging)
extras.setIsOfficialCredentials(true)
} catch (e: MicroBlogException) {
// Ignore
}
return Pair(AccountType.TWITTER, extras)
}
AccountType.FANFOU -> {
return Pair(AccountType.FANFOU, null)
}
else -> {
if (UserKeyUtils.isFanfouUser(user)) {
return Pair(AccountType.FANFOU, null)
}
2016-07-07 09:39:32 +02:00
}
}
return Pair(AccountType.TWITTER, null)
2016-07-07 09:39:32 +02:00
}
}
}