improved analyzer events

This commit is contained in:
Mariotaku Lee 2017-01-07 18:02:32 +08:00
parent 1aa3ac349c
commit ac7af6abac
17 changed files with 199 additions and 43 deletions

View File

@ -208,5 +208,5 @@ public interface IntentConstants {
String EXTRA_SIMPLE_LAYOUT = "simple_layout";
String EXTRA_API_CONFIG = "api_config";
String EXTRA_COUNT = "count";
String EXTRA_REQUEST_CODE = "request_code";
}

View File

@ -6,12 +6,15 @@ import android.os.Bundle
import android.support.v4.app.DialogFragment
import com.anjlab.android.iab.v3.BillingProcessor
import com.anjlab.android.iab.v3.Constants.*
import com.anjlab.android.iab.v3.SkuDetails
import com.anjlab.android.iab.v3.TransactionDetails
import nl.komponents.kovenant.task
import nl.komponents.kovenant.ui.alwaysUi
import nl.komponents.kovenant.ui.failUi
import nl.komponents.kovenant.ui.successUi
import org.mariotaku.twidere.Constants
import org.mariotaku.twidere.constant.EXTRA_CURRENCY
import org.mariotaku.twidere.constant.EXTRA_PRICE
import org.mariotaku.twidere.constant.IntentConstants.INTENT_PACKAGE_PREFIX
import org.mariotaku.twidere.constant.RESULT_NOT_PURCHASED
import org.mariotaku.twidere.constant.RESULT_SERVICE_UNAVAILABLE
@ -82,8 +85,9 @@ class GooglePlayInAppPurchaseActivity : BaseActivity(), BillingProcessor.IBillin
}
}
private fun handlePurchased(details: TransactionDetails) {
setResult(RESULT_OK)
private fun handlePurchased(sku: SkuDetails, transaction: TransactionDetails) {
val data = Intent().putExtra(EXTRA_PRICE, sku.priceValue).putExtra(EXTRA_CURRENCY, sku.currency)
setResult(RESULT_OK, data)
finish()
}
@ -93,11 +97,16 @@ class GooglePlayInAppPurchaseActivity : BaseActivity(), BillingProcessor.IBillin
val dfRef = WeakReference(ProgressDialogFragment.show(it.supportFragmentManager, "consume_purchase_progress"))
task {
val activity = weakThis.get() ?: throw PurchaseException(BILLING_RESPONSE_RESULT_USER_CANCELED)
activity.billingProcessor.loadOwnedPurchasesFromGoogle()
val details = activity.billingProcessor.getPurchaseTransactionDetails(activity.productId)
return@task details ?: throw PurchaseException(BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED)
}.successUi { details ->
weakThis.get()?.handlePurchased(details)
val productId = activity.productId
val bp = activity.billingProcessor
bp.loadOwnedPurchasesFromGoogle()
val skuDetails = bp.getPurchaseListingDetails(productId)
?: throw PurchaseException(BILLING_RESPONSE_RESULT_ERROR)
val transactionDetails = bp.getPurchaseTransactionDetails(productId)
?: throw PurchaseException(BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED)
return@task Pair(skuDetails, transactionDetails)
}.successUi { result ->
weakThis.get()?.handlePurchased(result.first, result.second)
}.failUi { error ->
if (error is PurchaseException) {
weakThis.get()?.handleError(error.code)
@ -122,10 +131,13 @@ class GooglePlayInAppPurchaseActivity : BaseActivity(), BillingProcessor.IBillin
val activity = weakThis.get() ?: throw PurchaseException(BILLING_RESPONSE_RESULT_USER_CANCELED)
val bp = activity.billingProcessor
bp.loadOwnedPurchasesFromGoogle()
val result = bp.getPurchaseTransactionDetails(activity.productId)
return@task result ?: throw PurchaseException(BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED)
}.successUi { details ->
weakThis.get()?.handlePurchased(details)
val skuDetails = bp.getPurchaseListingDetails(productId)
?: throw PurchaseException(BILLING_RESPONSE_RESULT_ERROR)
val transactionDetails = bp.getPurchaseTransactionDetails(productId)
?: throw PurchaseException(BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED)
return@task Pair(skuDetails, transactionDetails)
}.successUi { result ->
weakThis.get()?.handlePurchased(result.first, result.second)
}.failUi { error ->
if (error is PurchaseException) {
weakThis.get()?.handleError(error.code)
@ -149,6 +161,7 @@ class GooglePlayInAppPurchaseActivity : BaseActivity(), BillingProcessor.IBillin
BILLING_RESPONSE_RESULT_USER_CANCELED -> Activity.RESULT_CANCELED
BILLING_RESPONSE_RESULT_SERVICE_UNAVAILABLE -> RESULT_SERVICE_UNAVAILABLE
BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED -> RESULT_NOT_PURCHASED
BILLING_RESPONSE_RESULT_ERROR -> RESULT_NOT_PURCHASED
else -> billingResponse
}
return resultCode

View File

@ -22,6 +22,7 @@ package org.mariotaku.twidere.util
import android.accounts.Account
import android.accounts.AccountManager
import android.accounts.OnAccountsUpdateListener
import android.app.Activity
import android.app.Application
import android.os.Build
import com.crashlytics.android.Crashlytics
@ -32,9 +33,12 @@ 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.Purchase
import org.mariotaku.twidere.model.analyzer.Search
import org.mariotaku.twidere.model.analyzer.Share
import org.mariotaku.twidere.model.analyzer.SignIn
import java.math.BigDecimal
import java.util.*
/**
* Created by mariotaku on 15/7/8.
@ -81,6 +85,20 @@ class FabricAnalyzer : Analyzer(), Constants {
putAttributes(event)
})
}
is Purchase -> {
answers.logPurchase(configure(PurchaseEvent()) {
putItemName(event.productName)
putSuccess(event.resultCode == Activity.RESULT_OK)
if (!event.price.isNaN() && event.currency != null) {
putCurrency(Currency.getInstance(event.currency) ?: Currency.getInstance(Locale.getDefault()))
putItemPrice(BigDecimal(event.price))
}
event.forEachValues { name, value ->
putCustomAttribute(name, value)
}
putAttributes(event)
})
}
else -> {
answers.logCustom(configure(CustomEvent(event.name)) {
putAttributes(event)

View File

@ -108,6 +108,9 @@ public interface Constants extends TwidereConstants {
@Preference(type = STRING, exportable = false)
String KEY_DEVICE_SERIAL = "device_serial";
// Intent constants
String EXTRA_PRODUCT_TYPE = "product_type";
@SuppressWarnings("SpellCheckingInspection")
String GOOGLE_APIS_SERVER_CLIENT_ID = "223623398518-1p34hsndj7couh2c9c2f8909amh9euhf.apps.googleusercontent.com";
@SuppressWarnings("SpellCheckingInspection")

View File

@ -4,4 +4,8 @@ package org.mariotaku.twidere.constant
* Created by mariotaku on 2017/1/1.
*/
const val RESULT_SERVICE_UNAVAILABLE = 1
const val RESULT_NOT_PURCHASED = 8
const val RESULT_INTERNAL_ERROR = 6
const val RESULT_NOT_PURCHASED = 8
const val EXTRA_PRICE = "price"
const val EXTRA_CURRENCY = "currency"

View File

@ -242,3 +242,11 @@ private class BodyPartHandler(private val context: Context, private val draft: D
}
}
fun draftActionTypeString(@Draft.Action action: String?): String {
return when (action) {
Draft.Action.QUOTE -> "quote"
Draft.Action.REPLY -> "reply"
else -> "tweet"
}
}

View File

@ -0,0 +1,20 @@
package org.mariotaku.twidere.extension.model
import org.mariotaku.twidere.model.ParcelableMedia
/**
* Created by mariotaku on 2017/1/7.
*/
fun parcelableMediaTypeString(@ParcelableMedia.Type type: Int): String {
if (type <= 0) return "none"
return when (type) {
ParcelableMedia.Type.IMAGE -> "image"
ParcelableMedia.Type.VIDEO -> "video"
ParcelableMedia.Type.ANIMATED_GIF -> "gif"
ParcelableMedia.Type.CARD_ANIMATED_GIF -> "gif"
ParcelableMedia.Type.EXTERNAL_PLAYER -> "external"
ParcelableMedia.Type.VARIABLE_TYPE -> "variable"
else -> "unknown"
}
}

View File

@ -0,0 +1,9 @@
package org.mariotaku.twidere.extension.model
import org.mariotaku.twidere.model.ParcelableStatus
/**
* Created by mariotaku on 2017/1/7.
*/
val ParcelableStatus.media_type: Int
get() = (media ?: quoted_media)?.firstOrNull()?.type ?: 0

View File

@ -5,6 +5,7 @@ import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.view.View
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_REQUEST_CODE
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
/**
@ -26,7 +27,15 @@ class ExtraFeaturesIntroductionDialogFragment : BaseDialogFragment() {
builder.setTitle(R.string.title_extra_features)
builder.setView(R.layout.dialog_extra_features_introduction)
builder.setPositiveButton(R.string.action_purchase) { dialog, which ->
startActivity(extraFeaturesService.createPurchaseIntent(context))
val requestCode = arguments?.getInt(EXTRA_REQUEST_CODE) ?: 0
val purchaseIntent = extraFeaturesService.createPurchaseIntent(context)
if (requestCode == 0) {
startActivity(purchaseIntent)
} else if (parentFragment != null) {
parentFragment.startActivityForResult(purchaseIntent, requestCode)
} else {
activity.startActivityForResult(purchaseIntent, requestCode)
}
}
builder.setNegativeButton(R.string.action_later) { dialog, which ->

View File

@ -8,8 +8,7 @@ import android.support.v7.app.AlertDialog
import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.set
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_MESSAGE
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_PERMISSIONS
import org.mariotaku.twidere.constant.IntentConstants.*
/**
* Created by mariotaku on 2016/12/13.
@ -36,7 +35,7 @@ class PermissionRequestDialog : BaseDialogFragment() {
}
companion object {
const val EXTRA_REQUEST_CODE = "request_code"
fun show(fragmentManager: FragmentManager, message: String, permissions: Array<String>, requestCode: Int): PermissionRequestDialog {
val df = PermissionRequestDialog()
df.arguments = Bundle {

View File

@ -91,11 +91,13 @@ import org.mariotaku.twidere.annotation.Referral
import org.mariotaku.twidere.constant.*
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.*
import org.mariotaku.twidere.extension.model.getAccountType
import org.mariotaku.twidere.extension.model.media_type
import org.mariotaku.twidere.loader.ConversationLoader
import org.mariotaku.twidere.loader.ParcelableStatusLoader
import org.mariotaku.twidere.menu.FavoriteItemProvider
import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.analyzer.Share
import org.mariotaku.twidere.model.analyzer.StatusView
import org.mariotaku.twidere.model.message.FavoriteTaskEvent
import org.mariotaku.twidere.model.message.StatusListChangedEvent
import org.mariotaku.twidere.model.util.*
@ -208,7 +210,7 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
}
}
private val mStatusActivityLoaderCallback = object : LoaderCallbacks<StatusActivity?> {
private val statusActivityLoaderCallback = object : LoaderCallbacks<StatusActivity?> {
override fun onCreateLoader(id: Int, args: Bundle): Loader<StatusActivity?> {
val accountKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val statusId = args.getString(EXTRA_STATUS_ID)
@ -435,6 +437,7 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
event.isHasTranslateFeature = false
}
statusEvent = event
Analyzer.log(StatusView(details?.type, status.media_type))
} else if (readPosition != null) {
restoreReadPosition(readPosition)
}
@ -539,10 +542,10 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
args.putParcelable(EXTRA_ACCOUNT_KEY, status.account_key)
args.putString(EXTRA_STATUS_ID, if (status.is_retweet) status.retweet_id else status.id)
if (mActivityLoaderInitialized) {
loaderManager.restartLoader(LOADER_ID_STATUS_ACTIVITY, args, mStatusActivityLoaderCallback)
loaderManager.restartLoader(LOADER_ID_STATUS_ACTIVITY, args, statusActivityLoaderCallback)
return
}
loaderManager.initLoader(LOADER_ID_STATUS_ACTIVITY, args, mStatusActivityLoaderCallback)
loaderManager.initLoader(LOADER_ID_STATUS_ACTIVITY, args, statusActivityLoaderCallback)
mActivityLoaderInitialized = true
}

View File

@ -44,7 +44,6 @@ import android.widget.AutoCompleteTextView
import android.widget.ListView
import kotlinx.android.synthetic.main.fragment_content_listview.*
import org.mariotaku.ktextension.setGroupAvailability
import org.mariotaku.ktextension.setItemAvailability
import org.mariotaku.sqliteqb.library.Columns
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.R
@ -298,5 +297,6 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
internal const val REQUEST_ADD_USER_SELECT_ACCOUNT = 201
internal const val REQUEST_IMPORT_BLOCKS_SELECT_ACCOUNT = 202
internal const val REQUEST_IMPORT_MUTES_SELECT_ACCOUNT = 203
internal const val REQUEST_PURCHASE_EXTRA_FEATURES = 211
}
}

View File

@ -13,6 +13,7 @@ import android.view.MenuItem
import android.view.View
import android.widget.TextView
import org.mariotaku.kpreferences.KPreferences
import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.setItemAvailability
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.R
@ -21,12 +22,15 @@ import org.mariotaku.twidere.activity.AccountSelectorActivity
import org.mariotaku.twidere.activity.LinkHandlerActivity
import org.mariotaku.twidere.activity.UserListSelectorActivity
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_HOST
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_REQUEST_CODE
import org.mariotaku.twidere.constant.nameFirstKey
import org.mariotaku.twidere.fragment.ExtraFeaturesIntroductionDialogFragment
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.`FiltersData$UserItemCursorIndices`
import org.mariotaku.twidere.model.analyzer.Purchase
import org.mariotaku.twidere.provider.TwidereDataStore
import org.mariotaku.twidere.util.Analyzer
import org.mariotaku.twidere.util.ContentValuesCreator
import org.mariotaku.twidere.util.UserColorNameManager
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
@ -86,6 +90,9 @@ class FilteredUsersFragment : BaseFiltersFragment() {
intent.putExtra(EXTRA_ACCOUNT_KEY, data!!.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY))
startActivityForResult(intent, REQUEST_ADD_USER_SELECT_ACCOUNT)
}
REQUEST_PURCHASE_EXTRA_FEATURES -> {
Analyzer.log(Purchase.fromActivityResult(Purchase.NAME_EXTRA_FEATURES, resultCode, data))
}
}
}
@ -123,6 +130,9 @@ class FilteredUsersFragment : BaseFiltersFragment() {
startActivityForResult(intent, requestCode)
} else {
val df = ExtraFeaturesIntroductionDialogFragment()
df.arguments = Bundle {
putInt(EXTRA_REQUEST_CODE, REQUEST_PURCHASE_EXTRA_FEATURES)
}
df.show(childFragmentManager, "extra_features_introduction")
}
return true

View File

@ -13,6 +13,8 @@ import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.RESULT_NOT_PURCHASED
import org.mariotaku.twidere.constant.RESULT_SERVICE_UNAVAILABLE
import org.mariotaku.twidere.fragment.BaseSupportFragment
import org.mariotaku.twidere.model.analyzer.Purchase
import org.mariotaku.twidere.util.Analyzer
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
/**
@ -50,7 +52,12 @@ class ExtraFeaturesIntroductionCardFragment : BaseSupportFragment() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_PURCHASE -> {
activity?.recreate()
Analyzer.log(Purchase.fromActivityResult(Purchase.NAME_EXTRA_FEATURES, resultCode, data))
when (resultCode) {
Activity.RESULT_OK -> {
activity?.recreate()
}
}
}
REQUEST_RESTORE_PURCHASE -> {
when (resultCode) {

View File

@ -0,0 +1,48 @@
package org.mariotaku.twidere.model.analyzer
import android.app.Activity
import android.content.Intent
import org.mariotaku.twidere.constant.*
import org.mariotaku.twidere.util.Analyzer
/**
* Created by mariotaku on 2017/1/7.
*/
data class Purchase(val productName: String) : Analyzer.Event {
override val name: String = "Purchase"
override var accountType: String? = null
var resultCode: Int = Activity.RESULT_OK
var price: Double = Double.NaN
var currency: String? = null
override fun forEachValues(action: (String, String?) -> Unit) {
if (resultCode != Activity.RESULT_OK) {
action("Fail reason", getFailReason(resultCode))
}
}
companion object {
const val NAME_EXTRA_FEATURES = "Enhanced Features"
internal fun getFailReason(resultCode: Int): String {
return when (resultCode) {
Activity.RESULT_CANCELED -> "cancelled"
RESULT_SERVICE_UNAVAILABLE -> "service unavailable"
RESULT_INTERNAL_ERROR -> "internal error"
RESULT_NOT_PURCHASED -> "not purchased"
else -> "unknown"
}
}
fun fromActivityResult(name: String, resultCode: Int, data: Intent?): Purchase {
val result = Purchase(name)
result.resultCode = resultCode
if (data != null) {
result.price = data.getDoubleExtra(EXTRA_PRICE, Double.NaN)
result.currency = data.getStringExtra(EXTRA_CURRENCY)
}
return result
}
}
}

View File

@ -0,0 +1,22 @@
package org.mariotaku.twidere.model.analyzer
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.extension.model.parcelableMediaTypeString
import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.util.Analyzer
/**
* Created by mariotaku on 2017/1/7.
*/
data class StatusView(
@AccountType override val accountType: String? = null,
@ParcelableMedia.Type val mediaType: Int
) : Analyzer.Event {
override val name: String = "Status View"
override fun forEachValues(action: (String, String?) -> Unit) {
action("Media Type", parcelableMediaTypeString(mediaType))
}
}

View File

@ -1,6 +1,8 @@
package org.mariotaku.twidere.model.analyzer
import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.extension.model.draftActionTypeString
import org.mariotaku.twidere.extension.model.parcelableMediaTypeString
import org.mariotaku.twidere.model.Draft
import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.util.Analyzer
@ -30,29 +32,10 @@ data class UpdateStatus(
get() = "Tweet"
override fun forEachValues(action: (String, String?) -> Unit) {
action("Status Type", actionTypeString(actionType))
action("Media Type", mediaTypeString(mediaType))
action("Status Type", draftActionTypeString(actionType))
action("Media Type", parcelableMediaTypeString(mediaType))
action("Location Type", locationType)
action("Success", success.toString())
}
fun actionTypeString(@Draft.Action action: String?): String {
return when (action) {
Draft.Action.QUOTE -> "quote"
Draft.Action.REPLY -> "reply"
else -> "tweet"
}
}
fun mediaTypeString(@ParcelableMedia.Type type: Int): String {
return when (type) {
ParcelableMedia.Type.IMAGE -> "image"
ParcelableMedia.Type.VIDEO -> "video"
ParcelableMedia.Type.ANIMATED_GIF -> "gif"
ParcelableMedia.Type.CARD_ANIMATED_GIF -> "gif"
ParcelableMedia.Type.EXTERNAL_PLAYER -> "external"
ParcelableMedia.Type.VARIABLE_TYPE -> "variable"
else -> "unknown"
}
}
}