added account operations in debug mode

fixed share media for ExoPlayer
This commit is contained in:
Mariotaku Lee 2017-03-09 18:59:30 +08:00
parent 4d4f6f382d
commit 7dfc647797
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
13 changed files with 173 additions and 20 deletions

View File

@ -39,6 +39,7 @@ import com.fasterxml.jackson.core.JsonToken;
import com.hannesdorfmann.parcelableplease.annotation.ParcelableNoThanks;
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
import org.mariotaku.commons.logansquare.JsonStringConverter;
import org.mariotaku.twidere.annotation.AccountType;
import org.mariotaku.twidere.model.account.AccountExtras;
import org.mariotaku.twidere.model.account.cred.Credentials;
@ -85,12 +86,13 @@ public class AccountDetails implements Parcelable, Comparable<AccountDetails> {
@JsonField(name = "dummy")
public boolean dummy;
@JsonField(name = "credentials")
@JsonField(name = "credentials", typeConverter = JsonStringConverter.class)
@ParcelableNoThanks
String credentials_json;
public Credentials credentials;
@JsonField(name = "extras")
@JsonField(name = "extras", typeConverter = JsonStringConverter.class)
@ParcelableNoThanks
String extras_json;
public AccountExtras extras;

View File

@ -71,4 +71,11 @@ public class StatusNetAccountExtras implements Parcelable, AccountExtras {
public void writeToParcel(Parcel dest, int flags) {
StatusNetAccountExtrasParcelablePlease.writeToParcel(this, dest, flags);
}
@Override
public String toString() {
return "StatusNetAccountExtras{" +
"textLimit=" + textLimit +
'}';
}
}

View File

@ -71,4 +71,11 @@ public class TwitterAccountExtras implements Parcelable, AccountExtras {
public void writeToParcel(Parcel dest, int flags) {
TwitterAccountExtrasParcelablePlease.writeToParcel(this, dest, flags);
}
@Override
public String toString() {
return "TwitterAccountExtras{" +
"officialCredentials=" + officialCredentials +
'}';
}
}

View File

@ -50,6 +50,14 @@ public class BasicCredentials extends Credentials implements Parcelable {
BasicCredentialsParcelablePlease.writeToParcel(this, dest, flags);
}
@Override
public String toString() {
return "BasicCredentials{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
"} " + super.toString();
}
public static final Creator<BasicCredentials> CREATOR = new Creator<BasicCredentials>() {
public BasicCredentials createFromParcel(Parcel source) {
BasicCredentials target = new BasicCredentials();

View File

@ -65,6 +65,14 @@ public class Credentials implements Parcelable {
CredentialsParcelablePlease.writeToParcel(this, dest, flags);
}
@Override
public String toString() {
return "Credentials{" +
"api_url_format='" + api_url_format + '\'' +
", no_version_suffix=" + no_version_suffix +
'}';
}
public static final Creator<Credentials> CREATOR = new Creator<Credentials>() {
public Credentials createFromParcel(Parcel source) {
Credentials target = new Credentials();

View File

@ -44,6 +44,11 @@ public class EmptyCredentials extends Credentials implements Parcelable {
EmptyCredentialsParcelablePlease.writeToParcel(this, dest, flags);
}
@Override
public String toString() {
return "EmptyCredentials{} " + super.toString();
}
public static final Creator<EmptyCredentials> CREATOR = new Creator<EmptyCredentials>() {
public EmptyCredentials createFromParcel(Parcel source) {
EmptyCredentials target = new EmptyCredentials();

View File

@ -44,6 +44,11 @@ public class OAuth2Credentials extends Credentials implements Parcelable {
OAuth2CredentialsParcelablePlease.writeToParcel(this, dest, flags);
}
@Override
public String toString() {
return "OAuth2Credentials{} " + super.toString();
}
public static final Creator<OAuth2Credentials> CREATOR = new Creator<OAuth2Credentials>() {
public OAuth2Credentials createFromParcel(Parcel source) {
OAuth2Credentials target = new OAuth2Credentials();

View File

@ -58,6 +58,17 @@ public class OAuthCredentials extends Credentials implements Parcelable {
OAuthCredentialsParcelablePlease.writeToParcel(this, dest, flags);
}
@Override
public String toString() {
return "OAuthCredentials{" +
"consumer_key='" + consumer_key + '\'' +
", consumer_secret='" + consumer_secret + '\'' +
", access_token='" + access_token + '\'' +
", access_token_secret='" + access_token_secret + '\'' +
", same_oauth_signing_url=" + same_oauth_signing_url +
"} " + super.toString();
}
public static final Creator<OAuthCredentials> CREATOR = new Creator<OAuthCredentials>() {
public OAuthCredentials createFromParcel(Parcel source) {
OAuthCredentials target = new OAuthCredentials();

View File

@ -34,8 +34,8 @@ android {
applicationId "org.mariotaku.twidere"
minSdkVersion 14
targetSdkVersion 25
versionCode 297
versionName '3.4.35'
versionCode 298
versionName '3.4.36'
multiDexEnabled true
buildConfigField 'boolean', 'LEAK_CANARY_ENABLED', 'Boolean.parseBoolean("true")'
@ -117,6 +117,7 @@ dependencies {
debugCompile "com.facebook.stetho:stetho-okhttp3:${libVersions['Stetho']}"
debugCompile "com.facebook.stetho:stetho-js-rhino:${libVersions['Stetho']}"
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
debugCompile 'com.jayway.jsonpath:json-path:2.2.0'
provided 'javax.annotation:jsr250-api:1.0'

View File

@ -19,22 +19,35 @@
package org.mariotaku.twidere.util.stetho
import android.accounts.Account
import android.accounts.AccountManager
import android.content.Context
import android.util.Base64
import android.util.Base64InputStream
import android.util.Base64OutputStream
import com.bluelinelabs.logansquare.LoganSquare
import com.facebook.stetho.dumpapp.DumpException
import com.facebook.stetho.dumpapp.DumperContext
import com.facebook.stetho.dumpapp.DumperPlugin
import com.jayway.jsonpath.Configuration
import com.jayway.jsonpath.DocumentContext
import com.jayway.jsonpath.JsonPath
import com.jayway.jsonpath.TypeRef
import com.jayway.jsonpath.spi.json.JsonOrgJsonProvider
import com.jayway.jsonpath.spi.mapper.MappingProvider
import org.apache.commons.cli.GnuParser
import org.apache.commons.cli.Options
import org.json.JSONArray
import org.json.JSONObject
import org.mariotaku.ktextension.HexColorFormat
import org.mariotaku.ktextension.subArray
import org.mariotaku.ktextension.toHexColor
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.util.DataStoreUtils
import org.mariotaku.twidere.util.Utils
import java.io.File
import java.io.InputStream
import java.io.OutputStream
@ -99,12 +112,49 @@ class AccountsDumper(val context: Context) : DumperPlugin {
}
}
"list" -> {
val am = AccountManager.get(context)
val accounts = AccountUtils.getAllAccountDetails(am, true)
accounts.forEach {
dumpContext.stdout.println(it.key)
val keys = DataStoreUtils.getAccountKeys(context)
keys.forEach {
dumpContext.stdout.println(it)
}
}
"get" -> {
val subCommandArgs = argsAsList.subArray(1..argsAsList.lastIndex)
if (subCommandArgs.isEmpty()) {
throw DumpException("Account key required")
}
val docContext = try {
accountDocContext(subCommandArgs[0])
} catch (e: Utils.NoAccountException) {
throw DumpException("Account not found")
}
if (subCommandArgs.size == 1) {
val result = docContext.read("$", Object::class.java)
dumpContext.stdout.println(result?.prettyPrint())
} else for (i in 1..subCommandArgs.lastIndex) {
val result = docContext.read(subCommandArgs[i], Object::class.java)
dumpContext.stdout.println(result?.prettyPrint())
}
}
"set" -> {
val subCommandArgs = argsAsList.subArray(1..argsAsList.lastIndex)
if (subCommandArgs.size != 3) {
throw DumpException("Usage: accounts set <account_key> <field> <value>")
}
val docContext = try {
accountDocContext(subCommandArgs[0])
} catch (e: Utils.NoAccountException) {
throw DumpException("Account not found")
}
val value = subCommandArgs[2]
val path = subCommandArgs[1]
docContext.set(path, value)
val details = docContext.read("$", Object::class.java)?.let {
LoganSquare.parse(it.toString(), AccountDetails::class.java)
} ?: return
val am = AccountManager.get(context)
details.account.updateDetails(am, details)
dumpContext.stdout.println("$path = ${docContext.read(path, Object::class.java)?.prettyPrint()}")
}
else -> {
dumpContext.stderr.println("Usage: accounts [import|export] -p <password>")
}
@ -112,6 +162,25 @@ class AccountsDumper(val context: Context) : DumperPlugin {
}
private fun accountDocContext(forKey: String): DocumentContext {
val accountKey = UserKey.valueOf(forKey)
val am = AccountManager.get(context)
val details = AccountUtils.getAccountDetails(am, accountKey, true) ?: throw Utils.NoAccountException()
val configuration = Configuration.builder()
.jsonProvider(JsonOrgJsonProvider())
.mappingProvider(AsIsMappingProvider())
.build()
return JsonPath.parse(LoganSquare.serialize(details), configuration)
}
private fun Any.prettyPrint() = if (this is JSONObject) {
toString(4)
} else if (this is JSONArray) {
toString(4)
} else {
toString()
}
private fun exportAccounts(password: String, output: OutputStream) {
val secret = generateSecret(password)
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
@ -151,20 +220,24 @@ class AccountsDumper(val context: Context) : DumperPlugin {
if (account !in usedAccounts) {
am.addAccountExplicitly(account, null, null)
}
am.setUserData(account, ACCOUNT_USER_DATA_KEY, details.key.toString())
am.setUserData(account, ACCOUNT_USER_DATA_TYPE, details.type)
am.setUserData(account, ACCOUNT_USER_DATA_CREDS_TYPE, details.credentials_type)
am.setUserData(account, ACCOUNT_USER_DATA_ACTIVATED, true.toString())
am.setUserData(account, ACCOUNT_USER_DATA_COLOR, toHexColor(details.color, format = HexColorFormat.RGB))
am.setUserData(account, ACCOUNT_USER_DATA_USER, LoganSquare.serialize(details.user))
am.setUserData(account, ACCOUNT_USER_DATA_EXTRAS, details.extras?.let { LoganSquare.serialize(it) })
am.setAuthToken(account, ACCOUNT_AUTH_TOKEN_TYPE, LoganSquare.serialize(details.credentials))
account.updateDetails(am, details)
}
output.println("Done.")
}
private fun Account.updateDetails(am: AccountManager, details: AccountDetails) {
am.setUserData(this, ACCOUNT_USER_DATA_KEY, details.key.toString())
am.setUserData(this, ACCOUNT_USER_DATA_TYPE, details.type)
am.setUserData(this, ACCOUNT_USER_DATA_CREDS_TYPE, details.credentials_type)
am.setUserData(this, ACCOUNT_USER_DATA_ACTIVATED, true.toString())
am.setUserData(this, ACCOUNT_USER_DATA_COLOR, toHexColor(details.color, format = HexColorFormat.RGB))
am.setUserData(this, ACCOUNT_USER_DATA_USER, LoganSquare.serialize(details.user))
am.setUserData(this, ACCOUNT_USER_DATA_EXTRAS, details.extras?.let { LoganSquare.serialize(it) })
am.setAuthToken(this, ACCOUNT_AUTH_TOKEN_TYPE, LoganSquare.serialize(details.credentials))
}
fun ByteArray.toInt(): Int {
val bb = ByteBuffer.wrap(this)
bb.order(ByteOrder.LITTLE_ENDIAN)
@ -183,4 +256,17 @@ class AccountsDumper(val context: Context) : DumperPlugin {
return SecretKeySpec(factory.generateSecret(spec).encoded, "AES")
}
internal class AsIsMappingProvider : MappingProvider {
override fun <T : Any?> map(source: Any?, type: Class<T>, configuration: Configuration): T {
@Suppress("UNCHECKED_CAST")
return source as T
}
override fun <T : Any?> map(source: Any?, type: TypeRef<T>, configuration: Configuration): T {
@Suppress("UNCHECKED_CAST")
return source as T
}
}
}

View File

@ -60,7 +60,11 @@ class RawStreamDumper(val context: Context) : DumperPlugin {
userStream.getUserStreamRaw(object : RawCallback<MicroBlogException> {
override fun result(result: HttpResponse) {
dumpContext.stdout.println("Response: ${result.status}")
dumpContext.stdout.println("Headers: ${result.headers}")
dumpContext.stdout.println("Headers:")
result.headers.toList().forEach {
dumpContext.stdout.println("${it.first}: ${it.second}")
}
dumpContext.stdout.println()
result.body.writeTo(dumpContext.stdout)
}

View File

@ -197,7 +197,8 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
return true
}
R.id.share -> {
if (obj is CacheDownloadMediaViewerFragment) {
val fileInfo = obj.cacheFileInfo()
if (fileInfo != null) {
requestAndShareMedia(currentItem)
} else {
val media = media[currentItem]

View File

@ -134,6 +134,14 @@ fun <T> newMicroBlogInstance(context: Context, endpoint: Endpoint, auth: Authori
holder.connectionPool, holder.cache)
factory.setHttpClient(uploadHttpClient)
}
TwitterUserStream::class -> {
val conf = HttpClientFactory.HttpClientConfiguration(holder.preferences)
// Use longer read timeout for streaming
conf.readTimeoutSecs = 300
val uploadHttpClient = HttpClientFactory.createRestHttpClient(conf, holder.dns,
holder.connectionPool, holder.cache)
factory.setHttpClient(uploadHttpClient)
}
else -> {
factory.setHttpClient(holder.restHttpClient)
}