1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-02-09 00:08:41 +01:00

code cleanup

This commit is contained in:
Mariotaku Lee 2016-12-15 13:11:32 +08:00
parent 76ee626068
commit 44ac6750b0
61 changed files with 391 additions and 268 deletions

View File

@ -32,7 +32,7 @@ allprojects {
subprojects {
buildscript {
ext.kotlin_version = '1.0.5-2'
ext.android_support_lib_version = '25.0.1'
ext.android_support_lib_version = '25.1.0'
ext.mariotaku_commons_library_version = '0.9.11'
ext.mariotaku_restfu_version = '0.9.34'
}

View File

@ -1,56 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 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.util;
import android.app.Application;
import android.support.annotation.NonNull;
/**
* Created by mariotaku on 15/7/8.
*/
public abstract class BugReporter {
private static BugReporter sImplementation;
public static void setImplementation(BugReporter impl) {
sImplementation = impl;
}
public static void init(Application application) {
if (sImplementation == null) return;
sImplementation.initImpl(application);
}
public static void log(int priority, String tag, String msg) {
if (sImplementation == null) return;
sImplementation.logImpl(priority, tag, msg);
}
public static void logException(@NonNull Throwable throwable) {
if (sImplementation == null) return;
sImplementation.logExceptionImpl(throwable);
}
protected abstract void logImpl(int priority, String tag, String msg);
protected abstract void logExceptionImpl(@NonNull Throwable throwable);
protected abstract void initImpl(Application application);
}

View File

@ -65,6 +65,10 @@
<init>(android.content.Context);
}
-keep class * extends org.mariotaku.twidere.util.MapFragmentFactory
-keep class * extends org.mariotaku.twidere.util.TwitterCardFragmentFactory
-keep class * extends org.mariotaku.twidere.util.BugReporter
-keepclassmembers class * {
private <fields>;
}

View File

@ -0,0 +1,20 @@
package org.mariotaku.twidere.util
import android.support.test.runner.AndroidJUnit4
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.mariotaku.twidere.BuildConfig
/**
* Created by mariotaku on 2016/12/15.
*/
@RunWith(AndroidJUnit4::class)
class AnalyzerTest {
@Test
fun testGetInstance() {
if (BuildConfig.FLAVOR.contains("google")) {
Assert.assertNotNull(Analyzer.implementation)
}
}
}

View File

@ -0,0 +1,18 @@
package org.mariotaku.twidere.util
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
/**
* Created by mariotaku on 2016/12/15.
*/
@RunWith(AndroidJUnit4::class)
class MapFragmentFactoryTest {
@Test
fun testGetInstance() {
val context = InstrumentationRegistry.getTargetContext()
MapFragmentFactory.instance.createMapFragment(context = context)
}
}

View File

@ -0,0 +1,16 @@
package org.mariotaku.twidere.util
import android.support.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
/**
* Created by mariotaku on 2016/12/15.
*/
@RunWith(AndroidJUnit4::class)
class TwitterCardFragmentFactoryTest {
@Test
fun testGetInstance() {
TwitterCardFragmentFactory.instance
}
}

View File

@ -1,42 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 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.util;
import android.app.Application;
import android.support.annotation.NonNull;
/**
* Created by mariotaku on 15/7/8.
*/
public class TwidereBugReporter extends BugReporter {
@Override
protected void logImpl(int priority, String tag, String msg) {
}
@Override
protected void logExceptionImpl(@NonNull final Throwable throwable) {
}
@Override
protected void initImpl(final Application application) {
}
}

View File

@ -17,20 +17,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
package org.mariotaku.twidere.util
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.content.Context
import android.support.v4.app.Fragment
import org.mariotaku.twidere.fragment.OpenStreetMapViewerFragment;
import org.mariotaku.twidere.fragment.OpenStreetMapViewerFragment
/**
* Created by mariotaku on 15/4/27.
*/
public class MapFragmentFactoryImpl extends MapFragmentFactory {
@Override
public Fragment createMapFragment(@NonNull Context context) {
return new OpenStreetMapViewerFragment();
class OSMMapFragmentFactory : MapFragmentFactory() {
override fun createMapFragment(context: Context): Fragment {
return OpenStreetMapViewerFragment()
}
}

View File

@ -0,0 +1 @@
org.mariotaku.twidere.util.OSMMapFragmentFactory

View File

@ -0,0 +1 @@
org.mariotaku.twidere.util.TwitterCardFragmentFactoryImpl

View File

@ -25,25 +25,52 @@ import android.accounts.OnAccountsUpdateListener
import android.app.Application
import android.os.Build
import com.crashlytics.android.Crashlytics
import com.crashlytics.android.answers.Answers
import com.crashlytics.android.answers.AnswersEvent
import com.crashlytics.android.answers.LoginEvent
import com.crashlytics.android.answers.SearchEvent
import io.fabric.sdk.android.Fabric
import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe
import org.mariotaku.ktextension.configure
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.Constants
import org.mariotaku.twidere.TwidereConstants.ACCOUNT_TYPE
import org.mariotaku.twidere.model.analyzer.Search
import org.mariotaku.twidere.model.analyzer.SignIn
/**
* Created by mariotaku on 15/7/8.
*/
class TwidereBugReporter : BugReporter(), Constants {
class FabricAnalyzer : Analyzer(), Constants {
override fun logImpl(priority: Int, tag: String, msg: String) {
override fun log(priority: Int, tag: String, msg: String) {
Crashlytics.log(priority, tag, msg)
}
override fun logExceptionImpl(throwable: Throwable) {
override fun logException(throwable: Throwable) {
Crashlytics.logException(throwable)
}
override fun initImpl(application: Application) {
override fun log(event: Event) {
val answers = Answers.getInstance()
when (event) {
is SignIn -> {
answers.logLogin(configure(LoginEvent()) {
putMethod(event.type)
putSuccess(event.success)
putAttributes(event)
})
}
is Search -> {
answers.logSearch(configure(SearchEvent()) {
putQuery(event.query)
putAttributes(event)
})
}
}
}
override fun init(application: Application) {
Fabric.with(application, Crashlytics())
Crashlytics.setBool("debug", BuildConfig.DEBUG)
Crashlytics.setString("build.brand", Build.BRAND)
@ -55,8 +82,14 @@ class TwidereBugReporter : BugReporter(), Constants {
Crashlytics.setString("build.product", Build.PRODUCT)
val am = AccountManager.get(application)
am.addOnAccountsUpdatedListenerSafe(OnAccountsUpdateListener { accounts ->
Crashlytics.setString("twidere.accounts", accounts.joinToString(transform = Account::name))
Crashlytics.setString("twidere.accounts", accounts.filter { it.type == ACCOUNT_TYPE }
.joinToString(transform = Account::name))
}, updateImmediately = true)
}
private fun AnswersEvent<*>.putAttributes(event: Analyzer.Event) {
if (event.account != null) {
putCustomAttribute("account", event.account)
}
}
}

View File

@ -31,7 +31,7 @@ import org.mariotaku.twidere.fragment.WebMapFragment
/**
* Created by mariotaku on 15/4/27.
*/
class MapFragmentFactoryImpl : MapFragmentFactory() {
class GoogleMapFragmentFactory : MapFragmentFactory() {
override fun createMapFragment(context: Context): Fragment {
if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS) {

View File

@ -0,0 +1 @@
org.mariotaku.twidere.util.FabricAnalyzer

View File

@ -0,0 +1 @@
org.mariotaku.twidere.util.GoogleMapFragmentFactory

View File

@ -0,0 +1 @@
org.mariotaku.twidere.util.TwitterCardFragmentFactoryImpl

View File

@ -1,12 +0,0 @@
package android.support.v4.app;
public class BackStackEntryAccessor {
private BackStackEntryAccessor() {
}
public static Fragment getFragmentInBackStackRecord(final FragmentManager.BackStackEntry entry) {
if (entry instanceof BackStackRecord) return ((BackStackRecord) entry).mHead.fragment;
return null;
}
}

View File

@ -167,7 +167,7 @@ public class NetworkDiagnosticsFragment extends BaseSupportFragment {
publishProgress(LogText.LINEBREAK, LogText.LINEBREAK);
for (UserKey accountKey : DataStoreUtils.getAccountKeys(mContext)) {
final AccountDetails details = AccountUtils.getAccountDetails(AccountManager.get(mContext), accountKey);
final AccountDetails details = AccountUtils.getAccountDetails(AccountManager.get(mContext), accountKey, true);
final MicroBlog twitter = MicroBlogAPIFactory.getInstance(mContext, accountKey);
if (details == null || twitter == null) continue;
publishProgress(new LogText("Testing connection for account " + accountKey));

View File

@ -50,7 +50,7 @@ public class AccountPreferences implements Constants {
}
public int getDefaultNotificationLightColor() {
final AccountDetails a = AccountUtils.getAccountDetails(AccountManager.get(mContext), mAccountKey);
final AccountDetails a = AccountUtils.getAccountDetails(AccountManager.get(mContext), mAccountKey, true);
if (a != null) {
return a.color;
} else {

View File

@ -41,49 +41,52 @@ public class AccountUtils {
return am.getAccountsByType(ACCOUNT_TYPE);
}
public static AccountDetails[] getAllAccountDetails(@NonNull AccountManager am, @NonNull Account[] accounts) {
public static AccountDetails[] getAllAccountDetails(@NonNull AccountManager am, @NonNull Account[] accounts, boolean getCredentials) {
AccountDetails[] details = new AccountDetails[accounts.length];
for (int i = 0; i < accounts.length; i++) {
details[i] = getAccountDetails(am, accounts[i]);
details[i] = getAccountDetails(am, accounts[i], getCredentials);
}
Arrays.sort(details);
return details;
}
public static AccountDetails[] getAllAccountDetails(@NonNull AccountManager am, @NonNull UserKey[] accountKeys) {
public static AccountDetails[] getAllAccountDetails(@NonNull AccountManager am, @NonNull UserKey[] accountKeys, boolean getCredentials) {
AccountDetails[] details = new AccountDetails[accountKeys.length];
for (int i = 0; i < accountKeys.length; i++) {
details[i] = getAccountDetails(am, accountKeys[i]);
details[i] = getAccountDetails(am, accountKeys[i], getCredentials);
}
Arrays.sort(details);
return details;
}
public static AccountDetails[] getAllAccountDetails(@NonNull AccountManager am) {
return getAllAccountDetails(am, getAccounts(am));
public static AccountDetails[] getAllAccountDetails(@NonNull AccountManager am, boolean getCredentials) {
return getAllAccountDetails(am, getAccounts(am), getCredentials);
}
@Nullable
public static AccountDetails getAccountDetails(@NonNull AccountManager am, @NonNull UserKey accountKey) {
public static AccountDetails getAccountDetails(@NonNull AccountManager am, @NonNull UserKey accountKey, boolean getCredentials) {
final Account account = findByAccountKey(am, accountKey);
if (account == null) return null;
return getAccountDetails(am, account);
return getAccountDetails(am, account, getCredentials);
}
public static AccountDetails getAccountDetails(@NonNull AccountManager am, @NonNull Account account) {
public static AccountDetails getAccountDetails(@NonNull AccountManager am, @NonNull Account account, boolean getCredentials) {
AccountDetails details = new AccountDetails();
details.key = AccountExtensionsKt.getAccountKey(account, am);
details.account = account;
details.color = AccountExtensionsKt.getColor(account, am);
details.position = AccountExtensionsKt.getPosition(account, am);
details.credentials = AccountExtensionsKt.getCredentials(account, am);
details.user = AccountExtensionsKt.getAccountUser(account, am);
details.activated = AccountExtensionsKt.isActivated(account, am);
details.type = AccountExtensionsKt.getAccountType(account, am);
details.credentials_type = AccountExtensionsKt.getCredentialsType(account, am);
details.user = AccountExtensionsKt.getAccountUser(account, am);
details.user.color = details.color;
details.extras = AccountExtensionsKt.getAccountExtras(account, am);
details.user.color = details.color;
if (getCredentials) {
details.credentials = AccountExtensionsKt.getCredentials(account, am);
}
return details;
}
@ -97,7 +100,7 @@ public class AccountUtils {
}
public static boolean hasOfficialKeyAccount(Context context) {
for (AccountDetails details : getAllAccountDetails(AccountManager.get(context))) {
for (AccountDetails details : getAllAccountDetails(AccountManager.get(context), true)) {
if (AccountDetailsExtensionsKt.isOfficial(details, context)) {
return true;
}

View File

@ -18,7 +18,7 @@ public class ParcelableStatusUpdateUtils {
public static ParcelableStatusUpdate fromDraftItem(final Context context, final Draft draft) {
ParcelableStatusUpdate statusUpdate = new ParcelableStatusUpdate();
if (draft.account_keys != null) {
statusUpdate.accounts = AccountUtils.getAllAccountDetails(AccountManager.get(context), draft.account_keys);
statusUpdate.accounts = AccountUtils.getAllAccountDetails(AccountManager.get(context), draft.account_keys, true);
} else {
statusUpdate.accounts = new AccountDetails[0];
}

View File

@ -92,7 +92,7 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
protected void onAttachedToHierarchy(@NonNull final PreferenceManager preferenceManager) {
super.onAttachedToHierarchy(preferenceManager);
if (getPreferenceCount() > 0) return;
setAccountsData(AccountUtils.getAllAccountDetails(AccountManager.get(getContext())));
setAccountsData(AccountUtils.getAllAccountDetails(AccountManager.get(getContext()), true));
}
protected abstract void setupPreference(AccountItemPreference preference, AccountDetails account);

View File

@ -628,7 +628,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
@Override
protected SingleResponse<ParcelableStatus> doInBackground(final Object... params) {
final ContentResolver resolver = getContext().getContentResolver();
final AccountDetails details = AccountUtils.getAccountDetails(AccountManager.get(getContext()), mAccountKey);
final AccountDetails details = AccountUtils.getAccountDetails(AccountManager.get(getContext()), mAccountKey, true);
if (details == null) return SingleResponse.Companion.getInstance();
final MicroBlog microBlog = AccountDetailsExtensionsKt.newMicroBlogInstance(details,
getContext(), MicroBlog.class);
@ -1114,7 +1114,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
@Override
protected SingleResponse<ParcelableStatus> doInBackground(final Object... params) {
final AccountDetails details = AccountUtils.getAccountDetails(AccountManager.get(context), mAccountKey);
final AccountDetails details = AccountUtils.getAccountDetails(AccountManager.get(context), mAccountKey, true);
if (details == null) return SingleResponse.Companion.getInstance();
final MicroBlog microBlog = AccountDetailsExtensionsKt.newMicroBlogInstance(details,
getContext(), MicroBlog.class);
@ -1359,7 +1359,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
protected SingleResponse<ParcelableStatus> doInBackground(final Object... params) {
final ContentResolver resolver = getContext().getContentResolver();
final AccountDetails details = AccountUtils.getAccountDetails(AccountManager.get(getContext()),
mAccountKey);
mAccountKey, true);
if (details == null) return SingleResponse.Companion.getInstance();
final MicroBlog microBlog = AccountDetailsExtensionsKt.newMicroBlogInstance(details,
getContext(), MicroBlog.class);

View File

@ -93,8 +93,8 @@ public class MicroBlogAPIFactory implements TwidereConstants {
@WorkerThread
public static MicroBlog getInstance(@NonNull final Context context,
@NonNull final UserKey accountKey) {
AccountManager am = AccountManager.get(context);
Account account = AccountUtils.findByAccountKey(am, accountKey);
final AccountManager am = AccountManager.get(context);
final Account account = AccountUtils.findByAccountKey(am, accountKey);
if (account == null) return null;
final Credentials credentials = AccountExtensionsKt.getCredentials(account, am);
final String accountType = AccountExtensionsKt.getAccountType(account, am);

View File

@ -508,7 +508,7 @@ public final class Utils implements Constants {
}
public static boolean isOfficialCredentials(@NonNull final Context context, final UserKey accountKey) {
final AccountDetails details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey);
final AccountDetails details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true);
if (details == null) return false;
return AccountDetailsExtensionsKt.isOfficial(details, context);
}
@ -599,14 +599,14 @@ public final class Utils implements Constants {
if (t instanceof MicroBlogException)
return getTwitterErrorMessage(context, action, (MicroBlogException) t);
else if (t != null) return getErrorMessage(context, trimLineBreak(t.getMessage()));
TwidereBugReporter.logException(new IllegalStateException());
Analyzer.Companion.logException(new IllegalStateException());
return context.getString(R.string.error_unknown_error);
}
@Nullable
public static String getErrorMessage(@NonNull final Context context, final Throwable t) {
if (t == null) {
TwidereBugReporter.logException(new IllegalStateException());
Analyzer.Companion.logException(new IllegalStateException());
return context.getString(R.string.error_unknown_error);
}
if (t instanceof MicroBlogException)
@ -1189,10 +1189,10 @@ public final class Utils implements Constants {
if (appContext == null) return;
if (!appContext.getResources().getBoolean(R.bool.use_legacy_refresh_service)) return;
final Intent refreshServiceIntent = new Intent(appContext, RefreshService.class);
DataStoreUtils.prepareDatabase(context);
AsyncTask.execute(new Runnable() {
@Override
public void run() {
DataStoreUtils.prepareDatabase(context);
if (isNetworkAvailable(appContext) && hasAutoRefreshAccounts(appContext)) {
if (BuildConfig.DEBUG) {
Log.d(LOGTAG, "Start background refresh service");
@ -1471,7 +1471,7 @@ public final class Utils implements Constants {
try {
Menu.class.isAssignableFrom(MenuBuilder.class);
} catch (Error e) {
TwidereBugReporter.logException(e);
Analyzer.Companion.logException(e);
return false;
}
return true;

View File

@ -124,7 +124,7 @@ public class TwidereMediaDownloader implements MediaDownloader, Constants {
useThumbor = ((MediaExtra) extra).isUseThumbor();
UserKey accountKey = ((MediaExtra) extra).getAccountKey();
if (accountKey != null) {
account = AccountUtils.getAccountDetails(AccountManager.get(mContext), accountKey);
account = AccountUtils.getAccountDetails(AccountManager.get(mContext), accountKey, true);
if (account != null) {
auth = CredentialsExtensionsKt.getAuthorization(account.credentials);
}

View File

@ -39,6 +39,7 @@ import org.mariotaku.twidere.app.TwidereApplication
import org.mariotaku.twidere.extension.model.is_oauth
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.util.DataStoreUtils
class AccountSelectorActivity : BaseActivity(), OnClickListener, OnItemClickListener {
@ -83,12 +84,13 @@ class AccountSelectorActivity : BaseActivity(), OnClickListener, OnItemClickList
super.onCreate(savedInstanceState)
firstCreated = savedInstanceState == null
setContentView(R.layout.activity_account_selector)
DataStoreUtils.prepareDatabase(this)
adapter = AccountDetailsAdapter(this).apply {
setSwitchEnabled(!isSingleSelection)
setSortEnabled(false)
isProfileImageDisplayed = preferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true)
val am = AccountManager.get(context)
val allAccountDetails = AccountUtils.getAllAccountDetails(am, AccountUtils.getAccounts(am))
val allAccountDetails = AccountUtils.getAllAccountDetails(am, AccountUtils.getAccounts(am), false)
val extraKeys = keysWhiteList
val oAuthOnly = isOAuthOnly
val accountHost = accountHost

View File

@ -71,6 +71,7 @@ import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.ArrayRecyclerAdapter
import org.mariotaku.twidere.adapter.BaseRecyclerViewAdapter
import org.mariotaku.twidere.constant.*
import org.mariotaku.twidere.extension.getAccountUser
import org.mariotaku.twidere.fragment.BaseDialogFragment
import org.mariotaku.twidere.fragment.PermissionRequestDialog
import org.mariotaku.twidere.fragment.PermissionRequestDialog.PermissionRequestCancelCallback
@ -491,7 +492,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
finish()
return
}
val accountDetails = AccountUtils.getAllAccountDetails(am, accounts)
val accountDetails = AccountUtils.getAllAccountDetails(am, accounts, true)
val defaultAccountIds = accountDetails.map(AccountDetails::key).toTypedArray()
menuBar.setOnMenuItemClickListener(this)
setupEditText()
@ -994,7 +995,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
private fun handleReplyIntent(status: ParcelableStatus?): Boolean {
if (status == null) return false
val account = AccountUtils.getAccountDetails(AccountManager.get(this), status.account_key) ?: return false
val am = AccountManager.get(this)
val accountUser = AccountUtils.findByAccountKey(am, status.account_key)?.getAccountUser(am) ?: return false
var selectionStart = 0
val mentions = TreeSet(String.CASE_INSENSITIVE_ORDER)
editText.append("@" + status.user_screen_name + " ")
@ -1025,7 +1027,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
}
}
mentions.filterNot { it.equals(status.user_screen_name, ignoreCase = true) || it.equals(account.user.screen_name, ignoreCase = true) }
mentions.filterNot { it.equals(status.user_screen_name, ignoreCase = true)
|| it.equals(accountUser.screen_name, ignoreCase = true) }
.forEach { editText.append("@$it ") }
val selectionEnd = editText.length()
editText.setSelection(selectionStart, selectionEnd)
@ -1292,7 +1295,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
val isPossiblySensitive = hasMedia && possiblySensitive
val update = ParcelableStatusUpdate()
@Draft.Action val action = draft?.action_type ?: getDraftAction(intent.action)
update.accounts = AccountUtils.getAllAccountDetails(AccountManager.get(this), accountKeys)
update.accounts = AccountUtils.getAllAccountDetails(AccountManager.get(this), accountKeys, true)
update.text = text
if (attachLocation) {
update.location = recentLocation

View File

@ -58,12 +58,12 @@ import org.mariotaku.twidere.util.Utils.matchLinkId
class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IControlBarActivity, SupportFragmentCallback {
private val mControlBarShowHideHelper = ControlBarShowHideHelper(this)
private var mMultiSelectHandler: MultiSelectEventHandler? = null
private var mFinishOnly: Boolean = false
private var mActionBarHeight: Int = 0
private var mSubtitle: CharSequence? = null
private var mHideOffsetNotSupported: Boolean = false
private lateinit var multiSelectHandler: MultiSelectEventHandler
private lateinit var controlBarShowHideHelper: ControlBarShowHideHelper
private var finishOnly: Boolean = false
private var actionBarHeight: Int = 0
private var subtitle: CharSequence? = null
private var hideOffsetNotSupported: Boolean = false
override val currentVisibleFragment: Fragment?
@ -90,7 +90,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
if (mFinishOnly) {
if (finishOnly) {
finish()
} else {
NavUtils.navigateUpFromSameTask(this)
@ -142,17 +142,20 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
}
override fun onCreate(savedInstanceState: Bundle?) {
mMultiSelectHandler = MultiSelectEventHandler(this)
mMultiSelectHandler!!.dispatchOnCreate()
val intent = intent
super.onCreate(savedInstanceState)
multiSelectHandler = MultiSelectEventHandler(this)
controlBarShowHideHelper = ControlBarShowHideHelper(this)
multiSelectHandler.dispatchOnCreate()
val uri = intent.data
val linkId = matchLinkId(uri)
intent.setExtrasClassLoader(classLoader)
val fragment: Fragment?
val fragment: Fragment
try {
fragment = createFragmentForIntent(this, linkId, intent)
fragment = createFragmentForIntent(this, linkId, intent) ?: run {
finish()
return
}
} catch (e: Utils.NoAccountException) {
super.onCreate(savedInstanceState)
val selectIntent = Intent(this, AccountSelectorActivity::class.java)
val accountHost: String? = intent.getStringExtra(EXTRA_ACCOUNT_HOST) ?:
uri.getQueryParameter(QUERY_PARAM_ACCOUNT_HOST) ?: e.accountHost
@ -172,20 +175,13 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
}
}
super.onCreate(savedInstanceState)
if (fragment == null) {
finish()
return
}
setupActionBarOption()
Utils.logOpenNotificationFromUri(this, uri)
val ft = supportFragmentManager.beginTransaction()
ft.replace(android.R.id.content, fragment)
ft.commit()
setTitle(linkId, uri)
mFinishOnly = java.lang.Boolean.parseBoolean(uri.getQueryParameter(QUERY_PARAM_FINISH_ONLY))
finishOnly = java.lang.Boolean.parseBoolean(uri.getQueryParameter(QUERY_PARAM_FINISH_ONLY))
if (fragment is IToolBarSupportFragment) {
ThemeUtils.setCompatContentViewOverlay(window, EmptyDrawable())
@ -194,12 +190,12 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
override fun onStart() {
super.onStart()
mMultiSelectHandler!!.dispatchOnStart()
multiSelectHandler.dispatchOnStart()
}
override fun onStop() {
mMultiSelectHandler!!.dispatchOnStop()
multiSelectHandler.dispatchOnStop()
super.onStop()
}
@ -209,20 +205,20 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
}
fun setSubtitle(subtitle: CharSequence?) {
mSubtitle = subtitle
this.subtitle = subtitle
setupActionBarOption()
}
override fun setControlBarVisibleAnimate(visible: Boolean) {
// Currently only search page needs this pattern, so we only enable this feature for it.
if (currentVisibleFragment !is HideUiOnScroll) return
mControlBarShowHideHelper.setControlBarVisibleAnimate(visible)
controlBarShowHideHelper.setControlBarVisibleAnimate(visible)
}
override fun setControlBarVisibleAnimate(visible: Boolean, listener: ControlBarShowHideHelper.ControlBarAnimationListener) {
// Currently only search page needs this pattern, so we only enable this feature for it.
if (currentVisibleFragment !is HideUiOnScroll) return
mControlBarShowHideHelper.setControlBarVisibleAnimate(visible, listener)
controlBarShowHideHelper.setControlBarVisibleAnimate(visible, listener)
}
override fun getControlBarOffset(): Float {
@ -241,12 +237,12 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
val actionBar = supportActionBar
if (fragment is IToolBarSupportFragment) {
fragment.controlBarOffset = offset
} else if (actionBar != null && !mHideOffsetNotSupported) {
} else if (actionBar != null && !hideOffsetNotSupported) {
try {
actionBar.hideOffset = (controlBarHeight * offset).toInt()
} catch (e: UnsupportedOperationException) {
// Some device will throw this exception
mHideOffsetNotSupported = true
hideOffsetNotSupported = true
}
}
@ -261,9 +257,9 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
} else if (actionBar != null) {
return actionBar.height
}
if (mActionBarHeight != 0) return mActionBarHeight
mActionBarHeight = ThemeUtils.getActionBarHeight(this)
return mActionBarHeight
if (actionBarHeight != 0) return actionBarHeight
actionBarHeight = ThemeUtils.getActionBarHeight(this)
return actionBarHeight
}
private fun setTitle(linkId: Int, uri: Uri): Boolean {
@ -408,7 +404,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
val actionBar = supportActionBar
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true)
actionBar.subtitle = mSubtitle
actionBar.subtitle = subtitle
}
}
@ -459,7 +455,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
args.putDouble(EXTRA_LATITUDE, lat)
args.putDouble(EXTRA_LONGITUDE, lng)
}
fragment = MapFragmentFactory.getInstance().createMapFragment(context)
fragment = MapFragmentFactory.instance.createMapFragment(context)
}
LINK_ID_STATUS -> {
fragment = StatusFragment()
@ -721,6 +717,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
if (accountKey == null) {
val accountId = uri.getQueryParameter(CompatibilityConstants.QUERY_PARAM_ACCOUNT_ID)
val paramAccountName = uri.getQueryParameter(QUERY_PARAM_ACCOUNT_NAME)
DataStoreUtils.prepareDatabase(context)
if (accountId != null) {
accountKey = DataStoreUtils.findAccountKey(context, accountId)
args.putParcelable(EXTRA_ACCOUNT_KEY, accountKey)

View File

@ -39,6 +39,7 @@ import android.widget.AdapterView.OnItemClickListener
import android.widget.AdapterView.OnItemSelectedListener
import jopt.csp.util.SortableIntList
import kotlinx.android.synthetic.main.activity_quick_search_bar.*
import org.mariotaku.kpreferences.get
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.QUERY_PARAM_ACCOUNT_KEY
import org.mariotaku.twidere.TwidereConstants.QUERY_PARAM_QUERY
@ -47,7 +48,7 @@ import org.mariotaku.twidere.annotation.Referral
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEY
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.ACTION_NAVIGATION_BACK
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.CONTEXT_TAG_NAVIGATION
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NEW_DOCUMENT_API
import org.mariotaku.twidere.constant.newDocumentApiKey
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.AccountUtils
@ -96,7 +97,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
}
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor?> {
val accountId = selectedAccountKey
val accountId = selectedAccountDetails?.key
val builder = Suggestions.Search.CONTENT_URI.buildUpon()
builder.appendQueryParameter(QUERY_PARAM_QUERY, ParseUtils.parseString(searchQuery.text))
if (accountId != null) {
@ -125,19 +126,19 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
val item = adapter.getSuggestionItem(position)!!
when (adapter.getItemViewType(position)) {
SuggestionsAdapter.VIEW_TYPE_USER_SUGGESTION_ITEM -> {
IntentUtils.openUserProfile(this, selectedAccountKey,
IntentUtils.openUserProfile(this, selectedAccountDetails?.key,
UserKey.valueOf(item.extra_id!!), item.summary, null,
preferences.getBoolean(KEY_NEW_DOCUMENT_API),
preferences[newDocumentApiKey],
Referral.DIRECT)
finish()
}
SuggestionsAdapter.VIEW_TYPE_USER_SCREEN_NAME -> {
IntentUtils.openUserProfile(this, selectedAccountKey, null, item.title, null,
preferences.getBoolean(KEY_NEW_DOCUMENT_API), Referral.DIRECT)
IntentUtils.openUserProfile(this, selectedAccountDetails?.key, null, item.title,
null, preferences[newDocumentApiKey], Referral.DIRECT)
finish()
}
SuggestionsAdapter.VIEW_TYPE_SAVED_SEARCH, SuggestionsAdapter.VIEW_TYPE_SEARCH_HISTORY -> {
IntentUtils.openSearch(this, selectedAccountKey, item.title)
IntentUtils.openSearch(this, selectedAccountDetails?.key, item.title)
finish()
}
}
@ -168,7 +169,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_quick_search_bar)
val am = AccountManager.get(this)
val accounts = AccountUtils.getAllAccountDetails(am, AccountUtils.getAccounts(am)).toList()
val accounts = AccountUtils.getAllAccountDetails(am, AccountUtils.getAccounts(am), true).toList()
val accountsSpinnerAdapter = AccountsSpinnerAdapter(this, R.layout.spinner_item_account_icon)
accountsSpinnerAdapter.setDropDownViewResource(R.layout.list_item_simple_user)
accountsSpinnerAdapter.addAll(accounts)
@ -231,14 +232,14 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
if (isFinishing) return
val query = ParseUtils.parseString(searchQuery.text)
if (TextUtils.isEmpty(query)) return
IntentUtils.openSearch(this, selectedAccountKey, query)
val details = selectedAccountDetails ?: return
IntentUtils.openSearch(this, details.key, query)
finish()
}
private val selectedAccountKey: UserKey?
private val selectedAccountDetails: AccountDetails?
get() {
val account = accountSpinner.selectedItem as AccountDetails
return account.key
return accountSpinner.selectedItem as? AccountDetails
}
private fun updateWindowAttributes() {

View File

@ -52,6 +52,7 @@ import com.bluelinelabs.logansquare.LoganSquare
import com.rengwuxian.materialedittext.MaterialEditText
import kotlinx.android.synthetic.main.activity_sign_in.*
import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.convert
import org.mariotaku.ktextension.set
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException
@ -71,6 +72,8 @@ import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_API_CONFIG
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_CREDENTIALS_TYPE
import org.mariotaku.twidere.constant.defaultAPIConfigKey
import org.mariotaku.twidere.extension.getColor
import org.mariotaku.twidere.extension.model.official
import org.mariotaku.twidere.extension.newMicroBlogInstance
import org.mariotaku.twidere.fragment.BaseDialogFragment
import org.mariotaku.twidere.fragment.ProgressDialogFragment
@ -78,12 +81,14 @@ import org.mariotaku.twidere.model.CustomAPIConfig
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.SingleResponse
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.account.AccountExtras
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
import org.mariotaku.twidere.model.analyzer.SignIn
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.model.util.ParcelableUserUtils
import org.mariotaku.twidere.model.util.UserKeyUtils
@ -383,7 +388,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
result.updateAccount(am)
Toast.makeText(this, R.string.error_already_logged_in, Toast.LENGTH_SHORT).show()
} else {
result.addAccount(am)
val account = result.addAccount(am)
if (accountAuthenticatorResponse != null) {
accountAuthenticatorResult = Bundle {
this[AccountManager.KEY_BOOLEAN_RESULT] = true
@ -394,6 +399,8 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
startActivity(intent)
}
Analyzer.log(SignIn(true, type = result.accountType.first, account = account.name,
officialKey = result.accountType.second?.official ?: false))
finish()
}
}
@ -402,21 +409,29 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
if (BuildConfig.DEBUG) {
Log.w(LOGTAG, exception)
}
var errorReason: String? = null
if (exception is AuthenticityTokenException) {
Toast.makeText(this, R.string.wrong_api_key, Toast.LENGTH_SHORT).show()
errorReason = "wrong_api_key"
} else if (exception is WrongUserPassException) {
Toast.makeText(this, R.string.wrong_username_password, Toast.LENGTH_SHORT).show()
errorReason = "wrong_username_password"
} else if (exception is SignInTask.WrongBasicCredentialException) {
Toast.makeText(this, R.string.wrong_username_password, Toast.LENGTH_SHORT).show()
errorReason = "wrong_username_password"
} else if (exception is SignInTask.WrongAPIURLFormatException) {
Toast.makeText(this, R.string.wrong_api_key, Toast.LENGTH_SHORT).show()
errorReason = "wrong_api_key"
} else if (exception is LoginVerificationException) {
Toast.makeText(this, R.string.login_verification_failed, Toast.LENGTH_SHORT).show()
errorReason = "login_verification_failed"
} 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)
}
Analyzer.log(SignIn(false, type = "unknown", authType = apiConfig.credentialsType,
errorReason = errorReason))
}
internal fun dismissDialogFragment(tag: String) {
@ -543,9 +558,10 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
val userId = apiUser.id!!
val accountKey = UserKey(userId, UserKeyUtils.getUserHost(apiUser))
val user = ParcelableUserUtils.fromUser(apiUser, accountKey)
val account = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey)
val am = AccountManager.get(context)
val account = AccountUtils.findByAccountKey(am, accountKey)
if (account != null) {
color = account.color
color = account.getColor(am)
}
val credentials = OAuthCredentials()
credentials.api_url_format = apiUrlFormat
@ -717,7 +733,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
val credentials: Credentials,
val user: ParcelableUser,
val color: Int = 0,
val accountType: Pair<String, String?>
val accountType: Pair<String, AccountExtras?>
) {
private fun writeAccountInfo(action: (k: String, v: String?) -> Unit) {
@ -729,7 +745,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
action(ACCOUNT_USER_DATA_COLOR, toHexColor(color))
action(ACCOUNT_USER_DATA_USER, LoganSquare.serialize(user))
action(ACCOUNT_USER_DATA_EXTRAS, accountType.second)
action(ACCOUNT_USER_DATA_EXTRAS, accountType.second?.convert { LoganSquare.serialize(it) })
}
private fun writeAuthToken(am: AccountManager, account: Account) {
@ -856,9 +872,10 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
val accountType = SignInActivity.detectAccountType(twitter, apiUser)
val accountKey = UserKey(userId, UserKeyUtils.getUserHost(apiUser))
val user = ParcelableUserUtils.fromUser(apiUser, accountKey)
val account = AccountUtils.getAccountDetails(AccountManager.get(activity), accountKey)
val am = AccountManager.get(activity)
val account = AccountUtils.findByAccountKey(am, accountKey)
if (account != null) {
color = account.color
color = account.getColor(am)
}
val credentials = BasicCredentials()
credentials.api_url_format = apiUrlFormat
@ -885,9 +902,10 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
val accountType = SignInActivity.detectAccountType(twitter, apiUser)
val accountKey = UserKey(userId, UserKeyUtils.getUserHost(apiUser))
val user = ParcelableUserUtils.fromUser(apiUser, accountKey)
val account = AccountUtils.getAccountDetails(AccountManager.get(activity), accountKey)
val am = AccountManager.get(activity)
val account = AccountUtils.findByAccountKey(am, accountKey)
if (account != null) {
color = account.color
color = account.getColor(am)
}
val credentials = EmptyCredentials()
credentials.api_url_format = apiUrlFormat
@ -912,9 +930,10 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
val accountType = SignInActivity.detectAccountType(twitter, apiUser)
val accountKey = UserKey(userId, UserKeyUtils.getUserHost(apiUser))
val user = ParcelableUserUtils.fromUser(apiUser, accountKey)
val account = AccountUtils.getAccountDetails(AccountManager.get(activity), accountKey)
val am = AccountManager.get(activity)
val account = AccountUtils.findByAccountKey(am, accountKey)
if (account != null) {
color = account.color
color = account.getColor(am)
}
val credentials = OAuthCredentials()
credentials.api_url_format = apiUrlFormat
@ -992,17 +1011,16 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
private val EXTRA_API_LAST_CHANGE = "api_last_change"
private val DEFAULT_TWITTER_API_URL_FORMAT = "https://[DOMAIN.]twitter.com/"
internal fun detectAccountType(twitter: MicroBlog, user: User): Pair<String, String?> {
internal fun detectAccountType(twitter: MicroBlog, user: User): Pair<String, AccountExtras?> {
try {
// Get StatusNet specific resource
val config = twitter.statusNetConfig
val extra = StatusNetAccountExtras()
val extras = StatusNetAccountExtras()
val site = config.site
if (site != null) {
extra.textLimit = site.textLimit
extras.textLimit = site.textLimit
}
return Pair(AccountType.STATUSNET, JsonSerializer.serialize(extra,
StatusNetAccountExtras::class.java))
return Pair(AccountType.STATUSNET, extras)
} catch (e: MicroBlogException) {
// Ignore
}
@ -1012,10 +1030,9 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher {
val paging = Paging()
paging.count(1)
twitter.getActivitiesAboutMe(paging)
val extra = TwitterAccountExtras()
extra.setIsOfficialCredentials(true)
return Pair(AccountType.TWITTER, JsonSerializer.serialize(extra,
TwitterAccountExtras::class.java))
val extras = TwitterAccountExtras()
extras.setIsOfficialCredentials(true)
return Pair(AccountType.TWITTER, extras)
} catch (e: MicroBlogException) {
// Ignore
}

View File

@ -13,7 +13,7 @@ import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.app.TwidereApplication
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.util.BugReporter
import org.mariotaku.twidere.util.Analyzer
import org.mariotaku.twidere.util.IntentUtils
import org.mariotaku.twidere.util.Utils
@ -46,7 +46,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
startActivity(handled.first)
} else {
if (!handled.second) {
BugReporter.logException(TwitterLinkException("Unable to handle twitter uri " + uri))
Analyzer.logException(TwitterLinkException("Unable to handle twitter uri " + uri))
}
val fallbackIntent = Intent(Intent.ACTION_VIEW, uri)
fallbackIntent.addCategory(Intent.CATEGORY_BROWSABLE)

View File

@ -52,6 +52,7 @@ import org.mariotaku.mediaviewer.library.MediaDownloader
import org.mariotaku.restfu.http.RestHttpClient
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.Constants
import org.mariotaku.twidere.Constants.KEY_USAGE_STATISTICS
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.activity.AssistLauncherActivity
@ -72,6 +73,7 @@ import org.mariotaku.twidere.view.ProfileImageView
import org.mariotaku.twidere.view.TabPagerIndicator
import org.mariotaku.twidere.view.ThemedMultiValueSwitch
import org.mariotaku.twidere.view.TimelineContentTextView
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@ -251,18 +253,18 @@ class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeLis
private fun initBugReport() {
if (!sharedPreferences[bugReportsKey]) return
BugReporter.setImplementation(TwidereBugReporter())
BugReporter.init(this)
Analyzer.implementation = ServiceLoader.load(Analyzer::class.java).firstOrNull()
Analyzer.init(this)
}
private fun migrateUsageStatisticsPreferences() {
val preferences = sharedPreferences
val hasUsageStatistics = preferences.contains(Constants.KEY_USAGE_STATISTICS)
val hasUsageStatistics = preferences.contains(KEY_USAGE_STATISTICS)
if (hasUsageStatistics) return
if (preferences.contains(KEY_UCD_DATA_PROFILING) || preferences.contains(KEY_SPICE_DATA_PROFILING)) {
val prevUsageEnabled = preferences.getBoolean(KEY_UCD_DATA_PROFILING, false) || preferences.getBoolean(KEY_SPICE_DATA_PROFILING, false)
val editor = preferences.edit()
editor.putBoolean(Constants.KEY_USAGE_STATISTICS, prevUsageEnabled)
editor.putBoolean(KEY_USAGE_STATISTICS, prevUsageEnabled)
editor.remove(KEY_UCD_DATA_PROFILING)
editor.remove(KEY_SPICE_DATA_PROFILING)
editor.apply()

View File

@ -21,9 +21,10 @@ import org.mariotaku.twidere.util.toHexColor
fun Account.getCredentials(am: AccountManager): Credentials {
val credentialsType: String = getCredentialsType(am)
val creds: Credentials = parseCredentials(am.peekAuthToken(this, ACCOUNT_AUTH_TOKEN_TYPE), credentialsType)
return creds
val authToken = am.peekAuthToken(this, ACCOUNT_AUTH_TOKEN_TYPE) ?: run {
throw IllegalStateException("AuthToken is null for ${this}")
}
return parseCredentials(authToken, getCredentialsType(am))
}
@Credentials.Type
@ -32,7 +33,10 @@ fun Account.getCredentialsType(am: AccountManager): String {
}
fun Account.getAccountKey(am: AccountManager): UserKey {
return UserKey.valueOf(am.getUserData(this, ACCOUNT_USER_DATA_KEY))
val accountKeyString = am.getUserData(this, ACCOUNT_USER_DATA_KEY) ?: run {
throw IllegalStateException("UserKey is null for ${this}")
}
return UserKey.valueOf(accountKeyString)
}
fun Account.setAccountKey(am: AccountManager, accountKey: UserKey) {

View File

@ -4,6 +4,7 @@ import android.content.Context
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.extension.newMicroBlogInstance
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.account.AccountExtras
import org.mariotaku.twidere.model.account.TwitterAccountExtras
import org.mariotaku.twidere.model.account.cred.Credentials
import org.mariotaku.twidere.model.account.cred.OAuthCredentials
@ -23,6 +24,14 @@ fun AccountDetails.isOfficial(context: Context): Boolean {
return false
}
val AccountExtras.official: Boolean
get() {
if (this is TwitterAccountExtras) {
return isOfficialCredentials
}
return false
}
@JvmOverloads
fun <T> AccountDetails.newMicroBlogInstance(context: Context, includeEntities: Boolean = true, includeRetweets: Boolean = true,

View File

@ -727,7 +727,7 @@ class AccountsDashboardFragment : BaseSupportFragment(), LoaderCallbacks<Account
}
override fun loadInBackground(): AccountsInfo {
val accounts = AccountUtils.getAllAccountDetails(AccountManager.get(context))
val accounts = AccountUtils.getAllAccountDetails(AccountManager.get(context), true)
val draftsCount = DataStoreUtils.queryCount(context, Drafts.CONTENT_URI_UNSENT, null, null)
return AccountsInfo(accounts, draftsCount)
}

View File

@ -287,7 +287,7 @@ class CustomTabsFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>, Mult
accountsAdapter.add(AccountDetails.dummy())
}
val officialKeyOnly = arguments.getBoolean(EXTRA_OFFICIAL_KEY_ONLY, false)
accountsAdapter.addAll(AccountUtils.getAllAccountDetails(AccountManager.get(context)).filter {
accountsAdapter.addAll(AccountUtils.getAllAccountDetails(AccountManager.get(context), true).filter {
if (officialKeyOnly && !it.isOfficial(context)) {
return@filter false
}

View File

@ -171,7 +171,7 @@ class MessagesConversationFragment : BaseSupportFragment(), LoaderCallbacks<Curs
ActionBar.DISPLAY_SHOW_TITLE or ActionBar.DISPLAY_SHOW_CUSTOM)
actionBar.setCustomView(R.layout.layout_actionbar_message_user_picker)
val am = AccountManager.get(context)
val accounts = AccountUtils.getAllAccountDetails(am, AccountUtils.getAccounts(am)).asList()
val accounts = AccountUtils.getAllAccountDetails(am, AccountUtils.getAccounts(am), true).asList()
val accountsSpinnerAdapter = AccountsSpinnerAdapter(
actionBar.themedContext, R.layout.spinner_item_account_icon)
accountsSpinnerAdapter.setDropDownViewResource(R.layout.list_item_simple_user)
@ -244,7 +244,7 @@ class MessagesConversationFragment : BaseSupportFragment(), LoaderCallbacks<Curs
if (accountPos >= 0) {
account = accountsSpinnerAdapter.getItem(accountPos)
} else {
account = AccountUtils.getAccountDetails(AccountManager.get(activity), accountKey)
account = AccountUtils.getAccountDetails(AccountManager.get(activity), accountKey, true)
}
if (userId != null) {
recipient = Utils.getUserForConversation(activity, accountKey, userId)

View File

@ -47,7 +47,7 @@ import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.ParcelableStatusUpdate
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.service.BackgroundOperationService
import org.mariotaku.twidere.util.BugReporter
import org.mariotaku.twidere.util.Analyzer
import org.mariotaku.twidere.util.EditTextEnterHandler
import org.mariotaku.twidere.util.LinkCreator
import org.mariotaku.twidere.util.TwidereValidator
@ -63,7 +63,7 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
val builder = AlertDialog.Builder(context)
val context = builder.context
val status = status!!
val details = AccountUtils.getAccountDetails(AccountManager.get(context), status.account_key)!!
val details = AccountUtils.getAccountDetails(AccountManager.get(context), status.account_key, true)!!
builder.setView(R.layout.dialog_status_quote_retweet)
builder.setTitle(R.string.retweet_quote_confirm_title)
@ -159,7 +159,7 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
} else if (useQuote(!status.user_is_protected, details)) {
dismissDialog = retweetOrQuote(details, status, SHOW_PROTECTED_CONFIRM)
} else {
BugReporter.logException(IllegalStateException(status.toString()))
Analyzer.logException(IllegalStateException(status.toString()))
}
if (dismissDialog) {
dismiss()

View File

@ -19,6 +19,7 @@
package org.mariotaku.twidere.fragment
import android.accounts.AccountManager
import android.content.ContentValues
import android.content.Intent
import android.os.Bundle
@ -28,6 +29,7 @@ import android.text.TextUtils
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import org.mariotaku.ktextension.convert
import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.ComposeActivity
@ -38,9 +40,12 @@ import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCal
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.analyzer.Search
import org.mariotaku.twidere.model.tab.DrawableHolder
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.provider.RecentSearchProvider
import org.mariotaku.twidere.provider.TwidereDataStore.SearchHistory
import org.mariotaku.twidere.util.Analyzer
class SearchFragment : AbsToolbarTabPagesFragment(), RefreshScrollTopInterface, SupportFragmentCallback, SystemWindowsInsetsCallback, ControlBarOffsetListener, OnPageChangeListener, LinkHandlerActivity.HideUiOnScroll {
@ -55,16 +60,20 @@ class SearchFragment : AbsToolbarTabPagesFragment(), RefreshScrollTopInterface,
val values = ContentValues()
values.put(SearchHistory.QUERY, query)
context.contentResolver.insert(SearchHistory.CONTENT_URI, values)
Analyzer.log(Search(query, accountKey.convert {
AccountUtils.findByAccountKey(AccountManager.get(context), it)
}?.name))
}
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater!!.inflate(R.menu.menu_search, menu)
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_search, menu)
}
override fun onPrepareOptionsMenu(menu: Menu?) {
override fun onPrepareOptionsMenu(menu: Menu) {
if (isDetached || activity == null) return
val item = menu!!.findItem(R.id.compose)
val item = menu.findItem(R.id.compose)
item.title = getString(R.string.tweet_hashtag, query)
}

View File

@ -2058,7 +2058,7 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
override fun loadInBackground(): StatusActivity? {
val context = context
val details = AccountUtils.getAccountDetails(AccountManager.get(context), mAccountKey) ?: return null
val details = AccountUtils.getAccountDetails(AccountManager.get(context), mAccountKey, true) ?: return null
if (AccountType.TWITTER != details.type) {
return null
}

View File

@ -884,7 +884,7 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_KEY, user.account_key.toString())
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, user.key.toString())
val intent = Intent(Intent.ACTION_VIEW, builder.build())
intent.putExtra(EXTRA_ACCOUNT, AccountUtils.getAccountDetails(AccountManager.get(activity), user.account_key))
intent.putExtra(EXTRA_ACCOUNT, AccountUtils.getAccountDetails(AccountManager.get(activity), user.account_key, true))
intent.putExtra(EXTRA_USER, user)
startActivity(intent)
}
@ -1529,7 +1529,7 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
null, isFiltering))
}
val details = AccountUtils.getAccountDetails(AccountManager.get(context),
accountKey) ?: return SingleResponse.getInstance<ParcelableRelationship>(MicroBlogException("No Account"))
accountKey, true) ?: return SingleResponse.getInstance<ParcelableRelationship>(MicroBlogException("No Account"))
if (details.type == AccountType.TWITTER) {
if (!UserKeyUtils.isSameHost(accountKey, user.key)) {
return SingleResponse.getInstance(ParcelableRelationshipUtils.create(user, isFiltering))

View File

@ -348,7 +348,7 @@ class UserProfileEditorFragment : BaseSupportFragment(), OnSizeChangedListener,
) : AbstractTask<Context, SingleResponse<ParcelableUser>, UserProfileEditorFragment>() {
override fun doLongOperation(context: Context): SingleResponse<ParcelableUser> {
val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey) ?: return SingleResponse.getInstance()
val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true) ?: return SingleResponse.getInstance()
val microBlog = details.newMicroBlogInstance(context = context, cls = MicroBlog::class.java)
try {
var user: User? = null

View File

@ -140,7 +140,7 @@ class CardPollFragment : BaseSupportFragment(), LoaderManager.LoaderCallbacks<Pa
public override fun doLongOperation(cardDataMap: CardDataMap): ParcelableCardEntity? {
val details = AccountUtils.getAccountDetails(AccountManager.get(context),
card.account_key) ?: return null
card.account_key, true) ?: return null
val caps = details.newMicroBlogInstance(context, cls = TwitterCaps::class.java)
try {
val cardEntity = caps.sendPassThrough(cardDataMap).card
@ -233,7 +233,7 @@ class CardPollFragment : BaseSupportFragment(), LoaderManager.LoaderCallbacks<Pa
override fun onCreateLoader(id: Int, args: Bundle?): Loader<ParcelableCardEntity?> {
val card = card
val details = AccountUtils.getAccountDetails(AccountManager.get(context), card.account_key)!!
val details = AccountUtils.getAccountDetails(AccountManager.get(context), card.account_key, true)!!
return ParcelableCardEntityLoader(context, details, card.url, card.name)
}

View File

@ -26,7 +26,7 @@ class AccountDetailsLoader(
}
override fun loadInBackground(): List<AccountDetails> {
return AccountUtils.getAllAccountDetails(am).filter {
return AccountUtils.getAllAccountDetails(am, true).filter {
filter?.invoke(it) ?: true
}.sortedBy(AccountDetails::position)
}

View File

@ -91,7 +91,7 @@ abstract class MicroBlogAPIStatusesLoader(
override fun loadInBackground(): ListResponse<ParcelableStatus> {
val context = context
val accountKey = accountKey ?: return ListResponse.getListInstance<ParcelableStatus>(MicroBlogException("No Account"))
val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey) ?:
val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true) ?:
return ListResponse.getListInstance<ParcelableStatus>(MicroBlogException("No Account"))
var data: MutableList<ParcelableStatus>? = data

View File

@ -44,11 +44,11 @@ abstract class MicroBlogAPIUsersLoader(
override fun loadInBackground(): List<ParcelableUser> {
if (accountKey == null) {
return ListResponse.getListInstance<ParcelableUser>(MicroBlogException("No Account"))
return ListResponse.getListInstance(MicroBlogException("No Account"))
}
val am = AccountManager.get(context)
val details = AccountUtils.getAccountDetails(am, accountKey) ?:
return ListResponse.getListInstance<ParcelableUser>(MicroBlogException("No Account"))
val details = AccountUtils.getAccountDetails(am, accountKey, true) ?:
return ListResponse.getListInstance(MicroBlogException("No Account"))
val twitter: MicroBlog = details.newMicroBlogInstance(context = context, cls = MicroBlog::class.java)
val data = data
val users: List<User>

View File

@ -58,7 +58,7 @@ class ParcelableStatusLoader(
override fun loadInBackground(): SingleResponse<ParcelableStatus> {
if (accountKey == null || statusId == null) return SingleResponse.getInstance<ParcelableStatus>()
val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey)
val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true)
if (!omitIntentExtra && extras != null) {
val cache = extras.getParcelable<ParcelableStatus>(IntentConstants.EXTRA_STATUS)
if (cache != null) {

View File

@ -70,7 +70,7 @@ class ParcelableUserLoader(
val resolver = context.contentResolver
val accountKey = accountKey
val am = AccountManager.get(context)
val details = AccountUtils.getAllAccountDetails(am, AccountUtils.getAccounts(am)).firstOrNull {
val details = AccountUtils.getAllAccountDetails(am, AccountUtils.getAccounts(am), true).firstOrNull {
if (it.key == accountKey) {
return@firstOrNull true
} else if (it.user.account_key == accountKey) {

View File

@ -15,7 +15,7 @@ import org.mariotaku.twidere.model.util.AccountUtils
class AccountActionProvider(
context: Context,
var accounts: Array<AccountDetails>? = AccountUtils.getAllAccountDetails(AccountManager.get(context))
var accounts: Array<AccountDetails>? = AccountUtils.getAllAccountDetails(AccountManager.get(context), false)
) : ActionProvider(context), TwidereConstants {
var selectedAccountIds: Array<UserKey>? = null

View File

@ -0,0 +1,12 @@
package org.mariotaku.twidere.model.analyzer
import org.mariotaku.twidere.util.Analyzer
/**
* Created by mariotaku on 2016/12/15.
*/
data class Search(
val query: String,
override val account: String?
) : Analyzer.Event

View File

@ -0,0 +1,16 @@
package org.mariotaku.twidere.model.analyzer
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.util.Analyzer
/**
* Created by mariotaku on 2016/12/15.
*/
data class SignIn(
val success: Boolean,
@AccountType val type: String,
override val account: String? = null,
val officialKey: Boolean = false,
val authType: String? = null,
val errorReason: String? = null
) : Analyzer.Event

View File

@ -350,7 +350,7 @@ class BackgroundOperationService : IntentService("background_operation"), Consta
text: String,
imageUri: String?): SingleResponse<ParcelableDirectMessage> {
val details = AccountUtils.getAccountDetails(AccountManager.get(this),
accountKey) ?: return SingleResponse.getInstance<ParcelableDirectMessage>()
accountKey, true) ?: return SingleResponse.getInstance()
val twitter = details.newMicroBlogInstance(context = this, cls = MicroBlog::class.java)
val twitterUpload = details.newMicroBlogInstance(context = this, cls = TwitterUpload::class.java)
try {

View File

@ -94,7 +94,7 @@ class StreamingService : Service() {
}
private fun setTwitterInstances(): Boolean {
val accountsList = AccountUtils.getAllAccountDetails(AccountManager.get(this)).filter { it.credentials is OAuthCredentials }
val accountsList = AccountUtils.getAllAccountDetails(AccountManager.get(this), true).filter { it.credentials is OAuthCredentials }
val accountKeys = accountsList.map { it.key }.toTypedArray()
val activatedPreferences = AccountPreferences.getAccountPreferences(this, accountKeys)
if (BuildConfig.DEBUG) {

View File

@ -71,7 +71,7 @@ abstract class AbsFriendshipOperationTask(
}
public override fun doLongOperation(args: Arguments): SingleResponse<ParcelableUser> {
val details = AccountUtils.getAccountDetails(AccountManager.get(context), args.accountKey) ?: return SingleResponse.getInstance<ParcelableUser>()
val details = AccountUtils.getAccountDetails(AccountManager.get(context), args.accountKey, true) ?: return SingleResponse.getInstance()
val twitter = details.newMicroBlogInstance(context, cls = MicroBlog::class.java)
try {
val user = perform(twitter, details, args)

View File

@ -28,7 +28,7 @@ class DestroyStatusTask(
) : ManagedAsyncTask<Any, Any, SingleResponse<ParcelableStatus>>(context) {
override fun doInBackground(vararg params: Any): SingleResponse<ParcelableStatus> {
val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey)
val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true)
?: return SingleResponse()
val microBlog = details.newMicroBlogInstance(context, cls = MicroBlog::class.java)
var status: ParcelableStatus? = null

View File

@ -67,7 +67,7 @@ abstract class GetActivitiesTask(
for (i in accountIds.indices) {
val accountKey = accountIds[i]
val noItemsBefore = DataStoreUtils.getActivitiesCount(context, contentUri, accountKey) <= 0
val credentials = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey) ?: continue
val credentials = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true) ?: continue
val microBlog = credentials.newMicroBlogInstance(context = context, cls = MicroBlog::class.java)
val paging = Paging()
paging.count(loadItemLimit)

View File

@ -93,7 +93,7 @@ abstract class GetStatusesTask(
for (i in 0 until accountKeys.size) {
val accountKey = accountKeys[i]
val details = AccountUtils.getAccountDetails(AccountManager.get(context),
accountKey) ?: continue
accountKey, true) ?: continue
val microBlog = details.newMicroBlogInstance(context = context, cls = MicroBlog::class.java)
try {
val paging = Paging()

View File

@ -0,0 +1,61 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 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.util
import android.app.Application
/**
* Created by mariotaku on 15/7/8.
*/
abstract class Analyzer {
protected abstract fun log(priority: Int, tag: String, msg: String)
protected abstract fun log(event: Event)
protected abstract fun logException(throwable: Throwable)
protected abstract fun init(application: Application)
interface Event {
val account: String?
}
companion object {
var implementation: Analyzer? = null
fun init(application: Application) {
implementation?.init(application)
}
fun log(event: Event) {
implementation?.log(event)
}
fun log(priority: Int, tag: String, msg: String) {
implementation?.log(priority, tag, msg)
}
fun logException(throwable: Throwable) {
implementation?.logException(throwable)
}
}
}

View File

@ -21,6 +21,7 @@ package org.mariotaku.twidere.util
import android.content.Context
import android.support.v4.app.Fragment
import java.util.*
/**
* Created by mariotaku on 15/4/27.
@ -31,7 +32,8 @@ abstract class MapFragmentFactory {
companion object {
fun getInstance(): MapFragmentFactory = MapFragmentFactoryImpl()
val instance: MapFragmentFactory
get() = ServiceLoader.load(MapFragmentFactory::class.java).first()
}
}

View File

@ -115,7 +115,7 @@ object MenuUtils {
status: ParcelableStatus,
twitter: AsyncTwitterWrapper) {
val account = AccountUtils.getAccountDetails(AccountManager.get(context),
status.account_key) ?: return
status.account_key, true) ?: return
setupForStatus(context, preferences, menu, status, account, twitter)
}

View File

@ -27,6 +27,7 @@ import org.mariotaku.twidere.fragment.card.CardPollFragment
import org.mariotaku.twidere.model.ParcelableCardEntity
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.util.ParcelableCardEntityUtils
import java.util.*
/**
* Created by mariotaku on 15/1/1.
@ -42,7 +43,7 @@ abstract class TwitterCardFragmentFactory {
companion object {
val instance: TwitterCardFragmentFactory
get() = TwitterCardFragmentFactoryImpl()
get() = ServiceLoader.load(TwitterCardFragmentFactory::class.java).first()
fun createGenericPlayerFragment(card: ParcelableCardEntity?, args: Bundle?): Fragment? {
if (card == null) return null