added subscribe to filters link

This commit is contained in:
Mariotaku Lee 2017-01-19 01:48:29 +08:00
parent 87f2e604f4
commit 172e85ee42
11 changed files with 439 additions and 288 deletions

View File

@ -127,6 +127,7 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
String PATH_FILTERS_IMPORT_BLOCKS = "import/blocks"; String PATH_FILTERS_IMPORT_BLOCKS = "import/blocks";
String PATH_FILTERS_IMPORT_MUTES = "import/mutes"; String PATH_FILTERS_IMPORT_MUTES = "import/mutes";
String PATH_FILTERS_SUBSCRIPTIONS = "subscriptions"; String PATH_FILTERS_SUBSCRIPTIONS = "subscriptions";
String PATH_FILTERS_SUBSCRIPTIONS_ADD = "subscriptions/add";
String QUERY_PARAM_ACCOUNT_KEY = "account_key"; String QUERY_PARAM_ACCOUNT_KEY = "account_key";
String QUERY_PARAM_ACCOUNT_HOST = "account_host"; String QUERY_PARAM_ACCOUNT_HOST = "account_host";

View File

@ -13,7 +13,6 @@ import org.mariotaku.twidere.activity.premium.AbsExtraFeaturePurchaseActivity
*/ */
class GooglePlayExtraFeaturesService() : ExtraFeaturesService() { class GooglePlayExtraFeaturesService() : ExtraFeaturesService() {
private val PRODUCT_ID_EXTRA_FEATURES_PACK = "twidere.extra.features"
private lateinit var bp: BillingProcessor private lateinit var bp: BillingProcessor
@ -37,7 +36,12 @@ class GooglePlayExtraFeaturesService() : ExtraFeaturesService() {
} }
override fun destroyPurchase(): Boolean { override fun destroyPurchase(): Boolean {
return bp.consumePurchase(PRODUCT_ID_EXTRA_FEATURES_PACK) bp.consumePurchase(PRODUCT_ID_EXTRA_FEATURES_PACK)
bp.consumePurchase(PRODUCT_ID_DATA_SYNC)
bp.consumePurchase(PRODUCT_ID_FILTERS_IMPORT)
bp.consumePurchase(PRODUCT_ID_FILTERS_SUBSCRIPTION)
bp.consumePurchase(PRODUCT_ID_SCHEDULE_STATUS)
return true
} }
override fun createPurchaseIntent(context: Context, feature: String): Intent? { override fun createPurchaseIntent(context: Context, feature: String): Intent? {
@ -56,14 +60,20 @@ class GooglePlayExtraFeaturesService() : ExtraFeaturesService() {
} }
companion object { companion object {
private const val PRODUCT_ID_EXTRA_FEATURES_PACK = "twidere.extra.features"
private const val PRODUCT_ID_DATA_SYNC = "twidere.extra.feature.data_sync"
private const val PRODUCT_ID_FILTERS_IMPORT = "twidere.extra.feature.filter_import"
private const val PRODUCT_ID_FILTERS_SUBSCRIPTION = "twidere.extra.feature.filter_subscription"
private const val PRODUCT_ID_SCHEDULE_STATUS = "twidere.extra.feature.schedule_status"
@JvmStatic @JvmStatic
fun getProductId(feature: String): String { fun getProductId(feature: String): String {
return when (feature) { return when (feature) {
FEATURE_FEATURES_PACK -> "twidere.extra.features" FEATURE_FEATURES_PACK -> PRODUCT_ID_EXTRA_FEATURES_PACK
FEATURE_SYNC_DATA -> "twidere.extra.feature.data_sync" FEATURE_SYNC_DATA -> PRODUCT_ID_DATA_SYNC
FEATURE_FILTERS_IMPORT -> "twidere.extra.feature.filter_import" FEATURE_FILTERS_IMPORT -> PRODUCT_ID_FILTERS_IMPORT
FEATURE_FILTERS_SUBSCRIPTION -> "twidere.extra.feature.filter_subscription" FEATURE_FILTERS_SUBSCRIPTION -> PRODUCT_ID_FILTERS_SUBSCRIPTION
FEATURE_SCHEDULE_STATUS -> "twidere.extra.feature.schedule_status" FEATURE_SCHEDULE_STATUS -> PRODUCT_ID_SCHEDULE_STATUS
else -> throw UnsupportedOperationException(feature) else -> throw UnsupportedOperationException(feature)
} }
} }

View File

@ -1,87 +1,87 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest package="org.mariotaku.twidere" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
xmlns:tools="http://schemas.android.com/tools" package="org.mariotaku.twidere"
android:installLocation="internalOnly"> android:installLocation="internalOnly">
<uses-sdk tools:overrideLibrary="android.support.customtabs"/> <uses-sdk tools:overrideLibrary="android.support.customtabs" />
<uses-feature <uses-feature
android:name="android.hardware.camera" android:name="android.hardware.camera"
android:required="false"/> android:required="false" />
<uses-feature <uses-feature
android:name="android.hardware.telephony" android:name="android.hardware.telephony"
android:required="false"/> android:required="false" />
<uses-feature <uses-feature
android:name="android.hardware.location" android:name="android.hardware.location"
android:required="false"/> android:required="false" />
<uses-feature <uses-feature
android:name="android.hardware.location.gps" android:name="android.hardware.location.gps"
android:required="false"/> android:required="false" />
<uses-feature <uses-feature
android:name="android.hardware.location.network" android:name="android.hardware.location.network"
android:required="false"/> android:required="false" />
<uses-feature <uses-feature
android:name="android.hardware.touchscreen" android:name="android.hardware.touchscreen"
android:required="false"/> android:required="false" />
<uses-feature <uses-feature
android:name="android.hardware.nfc" android:name="android.hardware.nfc"
android:required="false"/> android:required="false" />
<uses-feature <uses-feature
android:glEsVersion="0x00020000" android:glEsVersion="0x00020000"
android:required="true"/> android:required="true" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.NFC"/> <uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- Used for account management --> <!-- Used for account management -->
<uses-permission <uses-permission
android:name="android.permission.GET_ACCOUNTS" android:name="android.permission.GET_ACCOUNTS"
android:maxSdkVersion="22"/> android:maxSdkVersion="22" />
<uses-permission <uses-permission
android:name="android.permission.MANAGE_ACCOUNTS" android:name="android.permission.MANAGE_ACCOUNTS"
android:maxSdkVersion="22"/> android:maxSdkVersion="22" />
<uses-permission <uses-permission
android:name="android.permission.AUTHENTICATE_ACCOUNTS" android:name="android.permission.AUTHENTICATE_ACCOUNTS"
android:maxSdkVersion="22"/> android:maxSdkVersion="22" />
<!-- Used for account sync --> <!-- Used for account sync -->
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/> <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="org.mariotaku.twidere.permission.SHORTEN_STATUS"/> <uses-permission android:name="org.mariotaku.twidere.permission.SHORTEN_STATUS" />
<uses-permission android:name="org.mariotaku.twidere.permission.UPLOAD_MEDIA"/> <uses-permission android:name="org.mariotaku.twidere.permission.UPLOAD_MEDIA" />
<uses-permission android:name="org.mariotaku.twidere.permission.SYNC_TIMELINE"/> <uses-permission android:name="org.mariotaku.twidere.permission.SYNC_TIMELINE" />
<uses-permission <uses-permission
android:name="android.permission.READ_PHONE_STATE" android:name="android.permission.READ_PHONE_STATE"
tools:node="remove"/> tools:node="remove" />
<permission-group <permission-group
android:name="org.mariotaku.twidere.permission.PERMISSION_GROUP" android:name="org.mariotaku.twidere.permission.PERMISSION_GROUP"
android:label="@string/app_name"/> android:label="@string/app_name" />
<permission <permission
android:name="org.mariotaku.twidere.permission.SHORTEN_STATUS" android:name="org.mariotaku.twidere.permission.SHORTEN_STATUS"
android:description="@string/permission_description_shorten_status" android:description="@string/permission_description_shorten_status"
android:label="@string/permission_label_shorten_status" android:label="@string/permission_label_shorten_status"
android:permissionGroup="org.mariotaku.twidere.permission.PERMISSION_GROUP"/> android:permissionGroup="org.mariotaku.twidere.permission.PERMISSION_GROUP" />
<permission <permission
android:name="org.mariotaku.twidere.permission.UPLOAD_MEDIA" android:name="org.mariotaku.twidere.permission.UPLOAD_MEDIA"
android:description="@string/permission_description_upload_media" android:description="@string/permission_description_upload_media"
android:label="@string/permission_label_upload_media" android:label="@string/permission_label_upload_media"
android:permissionGroup="org.mariotaku.twidere.permission.PERMISSION_GROUP"/> android:permissionGroup="org.mariotaku.twidere.permission.PERMISSION_GROUP" />
<permission <permission
android:name="org.mariotaku.twidere.permission.SYNC_TIMELINE" android:name="org.mariotaku.twidere.permission.SYNC_TIMELINE"
android:description="@string/permission_description_sync_timeline" android:description="@string/permission_description_sync_timeline"
android:label="@string/permission_label_sync_timeline" android:label="@string/permission_label_sync_timeline"
android:permissionGroup="org.mariotaku.twidere.permission.PERMISSION_GROUP"/> android:permissionGroup="org.mariotaku.twidere.permission.PERMISSION_GROUP" />
<application <application
android:name=".app.TwidereApplication" android:name=".app.TwidereApplication"
@ -99,32 +99,32 @@
tools:ignore="UnusedAttribute"> tools:ignore="UnusedAttribute">
<uses-library <uses-library
android:name="com.sec.android.app.multiwindow" android:name="com.sec.android.app.multiwindow"
android:required="false"/> android:required="false" />
<meta-data <meta-data
android:name="io.fabric.ApiKey" android:name="io.fabric.ApiKey"
android:value="dc4ee756d3b705e00011782f1426fc8656ad3bd9"/> android:value="dc4ee756d3b705e00011782f1426fc8656ad3bd9" />
<meta-data <meta-data
android:name="com.google.android.backup.api_key" android:name="com.google.android.backup.api_key"
android:value="AEdPqrEAAAAIKbKATV1AGbLB4kem3w8QaPVJSPVVumbMHxkfwA"/> android:value="AEdPqrEAAAAIKbKATV1AGbLB4kem3w8QaPVJSPVVumbMHxkfwA" />
<meta-data <meta-data
android:name="com.sec.android.support.multiwindow" android:name="com.sec.android.support.multiwindow"
android:value="true"/> android:value="true" />
<meta-data <meta-data
android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W" android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W"
android:value="480dp"/> android:value="480dp" />
<meta-data <meta-data
android:name="com.sec.android.multiwindow.DEFAULT_SIZE_H" android:name="com.sec.android.multiwindow.DEFAULT_SIZE_H"
android:value="640dp"/> android:value="640dp" />
<meta-data <meta-data
android:name="com.sec.android.multiwindow.MINIMUM_SIZE_W" android:name="com.sec.android.multiwindow.MINIMUM_SIZE_W"
android:value="240dp"/> android:value="240dp" />
<meta-data <meta-data
android:name="com.sec.android.multiwindow.MINIMUM_SIZE_H" android:name="com.sec.android.multiwindow.MINIMUM_SIZE_H"
android:value="320dp"/> android:value="320dp" />
<meta-data <meta-data
android:name="override_tinted_status_bar_defaults" android:name="override_tinted_status_bar_defaults"
android:value="true"/> android:value="true" />
<activity <activity
android:name=".activity.MainActivity" android:name=".activity.MainActivity"
@ -134,15 +134,15 @@
android:theme="@style/Theme.Twidere.NoActionBar" android:theme="@style/Theme.Twidere.NoActionBar"
android:windowSoftInputMode="adjustNothing"> android:windowSoftInputMode="adjustNothing">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER"/> <category android:name="android.intent.category.MULTIWINDOW_LAUNCHER" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.app.shortcuts" android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts"/> android:resource="@xml/compose_shortcuts" />
</activity> </activity>
<activity <activity
@ -154,15 +154,15 @@
android:theme="@style/Theme.Twidere.NoActionBar" android:theme="@style/Theme.Twidere.NoActionBar"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER"/> <category android:name="android.intent.category.MULTIWINDOW_LAUNCHER" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.app.shortcuts" android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts"/> android:resource="@xml/compose_shortcuts" />
</activity> </activity>
<activity <activity
@ -172,22 +172,22 @@
android:theme="@style/Theme.Twidere.NoActionBar" android:theme="@style/Theme.Twidere.NoActionBar"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="org.mariotaku.twidere.HOME"/> <action android:name="org.mariotaku.twidere.HOME" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEARCH"/> <action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.app.searchable" android:name="android.app.searchable"
android:resource="@xml/searchable"/> android:resource="@xml/searchable" />
<meta-data <meta-data
android:name="android.app.default_searchable" android:name="android.app.default_searchable"
android:value=".activity.support.HomeActivity"/> android:value=".activity.support.HomeActivity" />
</activity> </activity>
<activity <activity
android:name=".activity.ComposeActivity" android:name=".activity.ComposeActivity"
@ -198,31 +198,31 @@
android:theme="@style/Theme.Twidere.Compose" android:theme="@style/Theme.Twidere.Compose"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter android:label="@string/title_compose"> <intent-filter android:label="@string/title_compose">
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<action android:name="org.mariotaku.twidere.COMPOSE"/> <action android:name="org.mariotaku.twidere.COMPOSE" />
<action android:name="org.mariotaku.twidere.COMPOSE_TAKE_PHOTO"/> <action android:name="org.mariotaku.twidere.COMPOSE_TAKE_PHOTO" />
<action android:name="org.mariotaku.twidere.COMPOSE_PICK_IMAGE"/> <action android:name="org.mariotaku.twidere.COMPOSE_PICK_IMAGE" />
<action android:name="org.mariotaku.twidere.REPLY"/> <action android:name="org.mariotaku.twidere.REPLY" />
<action android:name="org.mariotaku.twidere.QUOTE"/> <action android:name="org.mariotaku.twidere.QUOTE" />
<action android:name="org.mariotaku.twidere.EDIT_DRAFT"/> <action android:name="org.mariotaku.twidere.EDIT_DRAFT" />
<action android:name="org.mariotaku.twidere.MENTION"/> <action android:name="org.mariotaku.twidere.MENTION" />
<action android:name="org.mariotaku.twidere.REPLY_MULTIPLE"/> <action android:name="org.mariotaku.twidere.REPLY_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<intent-filter android:label="@string/app_name"> <intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE"/> <action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*"/> <data android:mimeType="image/*" />
<data android:mimeType="text/plain"/> <data android:mimeType="text/plain" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.HomeActivity"/> android:value=".activity.HomeActivity" />
</activity> </activity>
<activity <activity
android:name=".activity.QuickSearchBarActivity" android:name=".activity.QuickSearchBarActivity"
@ -231,9 +231,9 @@
android:theme="@style/Theme.Twidere.QuickSearchBar" android:theme="@style/Theme.Twidere.QuickSearchBar"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="org.mariotaku.twidere.GLOBAL_SEARCH"/> <action android:name="org.mariotaku.twidere.GLOBAL_SEARCH" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@ -242,9 +242,9 @@
android:theme="@style/Theme.Twidere" android:theme="@style/Theme.Twidere"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="org.mariotaku.twidere.TWITTER_LOGIN"/> <action android:name="org.mariotaku.twidere.TWITTER_LOGIN" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@ -253,9 +253,9 @@
android:theme="@style/Theme.Twidere" android:theme="@style/Theme.Twidere"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="org.mariotaku.twidere.TWITTER_BROWSER_LOGIN"/> <action android:name="org.mariotaku.twidere.TWITTER_BROWSER_LOGIN" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@ -265,35 +265,35 @@
android:theme="@style/Theme.Twidere" android:theme="@style/Theme.Twidere"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE"/> <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
<action android:name="org.mariotaku.twidere.SETTINGS"/> <action android:name="org.mariotaku.twidere.SETTINGS" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.HomeActivity"/> android:value=".activity.HomeActivity" />
</activity> </activity>
<activity <activity
android:name=".activity.iface.APIEditorActivity" android:name=".activity.iface.APIEditorActivity"
android:label="@string/edit_api" android:label="@string/edit_api"
android:theme="@style/Theme.Twidere.Dialog" android:theme="@style/Theme.Twidere.Dialog"
android:windowSoftInputMode="adjustResize"/> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".activity.AccountSelectorActivity" android:name=".activity.AccountSelectorActivity"
android:label="@string/select_account" android:label="@string/select_account"
android:theme="@style/Theme.Twidere.Dialog"> android:theme="@style/Theme.Twidere.Dialog">
<intent-filter> <intent-filter>
<action android:name="org.mariotaku.twidere.SELECT_ACCOUNT"/> <action android:name="org.mariotaku.twidere.SELECT_ACCOUNT" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".activity.ColorPickerDialogActivity" android:name=".activity.ColorPickerDialogActivity"
android:label="@string/action_set_color" android:label="@string/action_set_color"
android:theme="@style/Theme.Twidere.NoDisplay"/> android:theme="@style/Theme.Twidere.NoDisplay" />
<activity <activity
android:name=".activity.LinkHandlerActivity" android:name=".activity.LinkHandlerActivity"
android:parentActivityName=".activity.HomeActivity" android:parentActivityName=".activity.HomeActivity"
@ -301,15 +301,15 @@
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.HomeActivity"/> android:value=".activity.HomeActivity" />
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE"/> <category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
<data android:scheme="twidere"/> <data android:scheme="twidere" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@ -320,17 +320,17 @@
android:windowSoftInputMode="adjustPan"> android:windowSoftInputMode="adjustPan">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.HomeActivity"/> android:value=".activity.HomeActivity" />
<intent-filter> <intent-filter>
<action android:name="org.mariotaku.twidere.VIEW_MEDIA"/> <action android:name="org.mariotaku.twidere.VIEW_MEDIA" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE"/> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http"/> <data android:scheme="http" />
<data android:scheme="https"/> <data android:scheme="https" />
<data android:scheme="file"/> <data android:scheme="file" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@ -340,10 +340,10 @@
android:theme="@style/Theme.Twidere.NoDisplay" android:theme="@style/Theme.Twidere.NoDisplay"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="org.mariotaku.twidere.PICK_FILE"/> <action android:name="org.mariotaku.twidere.PICK_FILE" />
<action android:name="org.mariotaku.twidere.PICK_DIRECTORY"/> <action android:name="org.mariotaku.twidere.PICK_DIRECTORY" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@ -352,11 +352,11 @@
android:theme="@style/Theme.Twidere.NoDisplay" android:theme="@style/Theme.Twidere.NoDisplay"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<action android:name="org.mariotaku.twidere.PICK_IMAGE"/> <action android:name="org.mariotaku.twidere.PICK_IMAGE" />
<action android:name="org.mariotaku.twidere.TAKE_PHOTO"/> <action android:name="org.mariotaku.twidere.TAKE_PHOTO" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@ -364,9 +364,9 @@
android:label="@string/title_compose" android:label="@string/title_compose"
android:theme="@style/Theme.Twidere.NoDisplay"> android:theme="@style/Theme.Twidere.NoDisplay">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT"/> <action android:name="android.intent.action.CREATE_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@ -374,9 +374,9 @@
android:label="@string/permissions_request" android:label="@string/permissions_request"
android:theme="@style/Theme.Twidere.Dialog"> android:theme="@style/Theme.Twidere.Dialog">
<intent-filter> <intent-filter>
<action android:name="org.mariotaku.twidere.REQUEST_PERMISSIONS"/> <action android:name="org.mariotaku.twidere.REQUEST_PERMISSIONS" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@ -384,38 +384,41 @@
android:label="@string/select_user_list" android:label="@string/select_user_list"
android:theme="@style/Theme.Twidere.Dialog"> android:theme="@style/Theme.Twidere.Dialog">
<intent-filter> <intent-filter>
<action android:name="org.mariotaku.twidere.SELECT_USER"/> <action android:name="org.mariotaku.twidere.SELECT_USER" />
<action android:name="org.mariotaku.twidere.SELECT_USER_LIST"/> <action android:name="org.mariotaku.twidere.SELECT_USER_LIST" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".activity.DataExportActivity" android:name=".activity.DataExportActivity"
android:label="@string/export_settings" android:label="@string/export_settings"
android:theme="@style/Theme.Twidere.NoDisplay"/> android:theme="@style/Theme.Twidere.NoDisplay" />
<activity <activity
android:name=".activity.DataImportActivity" android:name=".activity.DataImportActivity"
android:label="@string/import_settings" android:label="@string/import_settings"
android:theme="@style/Theme.Twidere.NoDisplay"/> android:theme="@style/Theme.Twidere.NoDisplay" />
<activity <activity
android:name=".activity.WebLinkHandlerActivity" android:name=".activity.WebLinkHandlerActivity"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:taskAffinity=":twidere_twitter_link_handler" android:taskAffinity=":twidere_twitter_link_handler"
android:theme="@style/Theme.Twidere.NoDisplay"> android:theme="@style/Theme.Twidere.NoDisplay">
<intent-filter> <intent-filter>
<data android:scheme="http"/> <data android:scheme="http" />
<data android:scheme="https"/> <data android:scheme="https" />
<data android:host="twitter.com"/> <data android:host="twitter.com" />
<data android:host="www.twitter.com"/> <data android:host="www.twitter.com" />
<data android:host="mobile.twitter.com"/> <data android:host="mobile.twitter.com" />
<data android:host="fanfou.com"/> <data android:host="fanfou.com" />
<data
android:host="twidere.mariotaku.org"
android:pathPrefix="/external" />
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW" />
<action android:name="android.nfc.action.NDEF_DISCOVERED"/> <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE"/> <category android:name="android.intent.category.BROWSABLE" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@ -425,51 +428,51 @@
android:taskAffinity=":twidere_assist_launcher" android:taskAffinity=":twidere_assist_launcher"
android:theme="@style/Theme.Twidere.NoDisplay"> android:theme="@style/Theme.Twidere.NoDisplay">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.ASSIST"/> <action android:name="android.intent.action.ASSIST" />
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="com.android.systemui.action_assist_icon" android:name="com.android.systemui.action_assist_icon"
android:resource="@drawable/ic_assist_twidere"/> android:resource="@drawable/ic_assist_twidere" />
</activity> </activity>
<activity <activity
android:name=".activity.KeyboardShortcutPreferenceCompatActivity" android:name=".activity.KeyboardShortcutPreferenceCompatActivity"
android:theme="@style/Theme.Twidere.Dialog"/> android:theme="@style/Theme.Twidere.Dialog" />
<activity <activity
android:name=".activity.HiddenSettingsActivity" android:name=".activity.HiddenSettingsActivity"
android:label="@string/hidden_settings" android:label="@string/hidden_settings"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/Theme.Twidere" android:theme="@style/Theme.Twidere"
android:windowSoftInputMode="adjustResize"/> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".activity.NyanActivity" android:name=".activity.NyanActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/Theme.Nyan" android:theme="@style/Theme.Nyan"
android:windowSoftInputMode="stateAlwaysHidden"/> android:windowSoftInputMode="stateAlwaysHidden" />
<activity <activity
android:name=".activity.UsageStatisticsActivity" android:name=".activity.UsageStatisticsActivity"
android:label="@string/usage_statistics" android:label="@string/usage_statistics"
android:theme="@style/Theme.Twidere"/> android:theme="@style/Theme.Twidere" />
<activity <activity
android:name=".activity.ImageCropperActivity" android:name=".activity.ImageCropperActivity"
android:label="@string/crop_image" android:label="@string/crop_image"
android:theme="@style/Theme.Twidere.NoActionBar" android:theme="@style/Theme.Twidere.NoActionBar"
android:windowSoftInputMode="adjustResize"/> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".activity.IncompatibleAlertActivity" android:name=".activity.IncompatibleAlertActivity"
android:label="@string/error_title_device_incompatible" android:label="@string/error_title_device_incompatible"
android:theme="@android:style/Theme.DeviceDefault.Dialog"/> android:theme="@android:style/Theme.DeviceDefault.Dialog" />
<activity <activity
android:name=".activity.InvalidAccountAlertActivity" android:name=".activity.InvalidAccountAlertActivity"
android:theme="@style/Theme.Twidere.NoDisplay"/> android:theme="@style/Theme.Twidere.NoDisplay" />
<activity <activity
android:name=".activity.FragmentContentActivity" android:name=".activity.FragmentContentActivity"
android:theme="@style/Theme.Twidere"> android:theme="@style/Theme.Twidere">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.HomeActivity"/> android:value=".activity.HomeActivity" />
</activity> </activity>
<activity <activity
android:name=".activity.PremiumDashboardActivity" android:name=".activity.PremiumDashboardActivity"
@ -478,35 +481,35 @@
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.HomeActivity"/> android:value=".activity.HomeActivity" />
</activity> </activity>
<service <service
android:name=".service.LegacyTaskService" android:name=".service.LegacyTaskService"
android:enabled="@bool/use_legacy_refresh_service" android:enabled="@bool/use_legacy_refresh_service"
android:label="@string/label_refresh_and_sync_service"/> android:label="@string/label_refresh_and_sync_service" />
<service <service
android:name=".service.JobTaskService" android:name=".service.JobTaskService"
android:enabled="@bool/use_job_refresh_service" android:enabled="@bool/use_job_refresh_service"
android:exported="true" android:exported="true"
android:label="@string/label_refresh_and_sync_service" android:label="@string/label_refresh_and_sync_service"
android:permission="android.permission.BIND_JOB_SERVICE"/> android:permission="android.permission.BIND_JOB_SERVICE" />
<service <service
android:name=".service.StreamingService" android:name=".service.StreamingService"
android:label="@string/label_streaming_service"/> android:label="@string/label_streaming_service" />
<service <service
android:name=".service.LengthyOperationsService" android:name=".service.LengthyOperationsService"
android:label="@string/label_background_operation_service"/> android:label="@string/label_background_operation_service" />
<service <service
android:name=".service.AccountAuthenticatorService" android:name=".service.AccountAuthenticatorService"
android:exported="true" android:exported="true"
tools:ignore="ExportedService"> tools:ignore="ExportedService">
<intent-filter> <intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/> <action android:name="android.accounts.AccountAuthenticator" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.accounts.AccountAuthenticator" android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/account_authenticator"/> android:resource="@xml/account_authenticator" />
</service> </service>
<service <service
android:name=".service.AccountSyncService" android:name=".service.AccountSyncService"
@ -514,11 +517,11 @@
android:process=":sync" android:process=":sync"
tools:ignore="ExportedService"> tools:ignore="ExportedService">
<intent-filter> <intent-filter>
<action android:name="android.content.SyncAdapter"/> <action android:name="android.content.SyncAdapter" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.content.SyncAdapter" android:name="android.content.SyncAdapter"
android:resource="@xml/sync_adapter"/> android:resource="@xml/sync_adapter" />
</service> </service>
<service <service
@ -530,12 +533,12 @@
android:permission="android.permission.BIND_WALLPAPER" android:permission="android.permission.BIND_WALLPAPER"
android:process=":wallpaper"> android:process=":wallpaper">
<intent-filter android:priority="1"> <intent-filter android:priority="1">
<action android:name="android.service.wallpaper.WallpaperService"/> <action android:name="android.service.wallpaper.WallpaperService" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.service.wallpaper" android:name="android.service.wallpaper"
android:resource="@xml/nyan_wallpaper"/> android:resource="@xml/nyan_wallpaper" />
</service> </service>
<service <service
android:name=".nyan.NyanDaydreamService" android:name=".nyan.NyanDaydreamService"
@ -546,10 +549,10 @@
android:process=":daydream" android:process=":daydream"
tools:ignore="ExportedService"> tools:ignore="ExportedService">
<intent-filter android:priority="1"> <intent-filter android:priority="1">
<action android:name="android.service.dreams.DreamService"/> <action android:name="android.service.dreams.DreamService" />
</intent-filter> </intent-filter>
</service> </service>
<service android:name="edu.tsinghua.hotmobi.UploadLogsService"/> <service android:name="edu.tsinghua.hotmobi.UploadLogsService" />
<provider <provider
android:name=".provider.TwidereDataProvider" android:name=".provider.TwidereDataProvider"
@ -557,20 +560,20 @@
android:exported="true" android:exported="true"
android:grantUriPermissions="true" android:grantUriPermissions="true"
android:label="@string/label_data_provider" android:label="@string/label_data_provider"
tools:ignore="ExportedContentProvider"/> tools:ignore="ExportedContentProvider" />
<provider <provider
android:name=".provider.RecentSearchProvider" android:name=".provider.RecentSearchProvider"
android:authorities="org.mariotaku.twidere.provider.SearchRecentSuggestions" android:authorities="org.mariotaku.twidere.provider.SearchRecentSuggestions"
tools:ignore="ExportedContentProvider"/> tools:ignore="ExportedContentProvider" />
<provider <provider
android:name=".provider.CacheProvider" android:name=".provider.CacheProvider"
android:authorities="twidere.cache" android:authorities="twidere.cache"
android:exported="false"/> android:exported="false" />
<provider <provider
android:name=".provider.ShareProvider" android:name=".provider.ShareProvider"
android:authorities="twidere.share" android:authorities="twidere.share"
android:exported="true" android:exported="true"
tools:ignore="ExportedContentProvider"/> tools:ignore="ExportedContentProvider" />
<provider <provider
android:name="android.support.v4.content.FileProvider" android:name="android.support.v4.content.FileProvider"
android:authorities="org.mariotaku.twidere.pncfileprovider" android:authorities="org.mariotaku.twidere.pncfileprovider"
@ -578,30 +581,30 @@
android:grantUriPermissions="true"> android:grantUriPermissions="true">
<meta-data <meta-data
android:name="android.support.FILE_PROVIDER_PATHS" android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/pickncrop__file_paths"/> android:resource="@xml/pickncrop__file_paths" />
</provider> </provider>
<receiver android:name=".receiver.ConnectivityStateReceiver"> <receiver android:name=".receiver.ConnectivityStateReceiver">
<intent-filter> <intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver <receiver
android:name=".receiver.NotificationReceiver" android:name=".receiver.NotificationReceiver"
android:exported="false"> android:exported="false">
<intent-filter> <intent-filter>
<action android:name="org.mariotaku.twidere.NOTIFICATION_DELETED"/> <action android:name="org.mariotaku.twidere.NOTIFICATION_DELETED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver <receiver
android:name=".receiver.SecretCodeBroadcastReceiver" android:name=".receiver.SecretCodeBroadcastReceiver"
android:label="@string/twidere_test"> android:label="@string/twidere_test">
<intent-filter> <intent-filter>
<action android:name="android.provider.Telephony.SECRET_CODE"/> <action android:name="android.provider.Telephony.SECRET_CODE" />
<data <data
android:host="8943373" android:host="8943373"
android:scheme="android_secret_code"/> android:scheme="android_secret_code" />
</intent-filter> </intent-filter>
</receiver> </receiver>

View File

@ -79,6 +79,7 @@ public interface Constants extends TwidereConstants {
int LINK_ID_FILTERS_IMPORT_BLOCKS = 111; int LINK_ID_FILTERS_IMPORT_BLOCKS = 111;
int LINK_ID_FILTERS_IMPORT_MUTES = 112; int LINK_ID_FILTERS_IMPORT_MUTES = 112;
int LINK_ID_FILTERS_SUBSCRIPTIONS = 113; int LINK_ID_FILTERS_SUBSCRIPTIONS = 113;
int LINK_ID_FILTERS_SUBSCRIPTIONS_ADD = 114;
int LINK_ID_PROFILE_EDITOR = 121; int LINK_ID_PROFILE_EDITOR = 121;
String TWIDERE_PREVIEW_NICKNAME = "Twidere"; String TWIDERE_PREVIEW_NICKNAME = "Twidere";

View File

@ -155,51 +155,10 @@ public final class Utils implements Constants {
public static final Pattern PATTERN_XML_RESOURCE_IDENTIFIER = Pattern.compile("res/xml/([\\w_]+)\\.xml"); public static final Pattern PATTERN_XML_RESOURCE_IDENTIFIER = Pattern.compile("res/xml/([\\w_]+)\\.xml");
public static final Pattern PATTERN_RESOURCE_IDENTIFIER = Pattern.compile("@([\\w_]+)/([\\w_]+)"); public static final Pattern PATTERN_RESOURCE_IDENTIFIER = Pattern.compile("@([\\w_]+)/([\\w_]+)");
private static final UriMatcher LINK_HANDLER_URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
private static final UriMatcher HOME_TABS_URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); private static final UriMatcher HOME_TABS_URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
static { static {
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_STATUS, null, LINK_ID_STATUS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER, null, LINK_ID_USER);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_TIMELINE, null, LINK_ID_USER_TIMELINE);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_MEDIA_TIMELINE, null, LINK_ID_USER_MEDIA_TIMELINE);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_FOLLOWERS, null, LINK_ID_USER_FOLLOWERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_FRIENDS, null, LINK_ID_USER_FRIENDS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_FAVORITES, null, LINK_ID_USER_FAVORITES);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_BLOCKS, null, LINK_ID_USER_BLOCKS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_DIRECT_MESSAGES_CONVERSATION, null,
LINK_ID_DIRECT_MESSAGES_CONVERSATION);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_DIRECT_MESSAGES, null, LINK_ID_DIRECT_MESSAGES);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_INTERACTIONS, null, LINK_ID_INTERACTIONS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_PUBLIC_TIMELINE, null, LINK_ID_PUBLIC_TIMELINE);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LIST, null, LINK_ID_USER_LIST);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_GROUP, null, LINK_ID_GROUP);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LIST_TIMELINE, null, LINK_ID_USER_LIST_TIMELINE);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LIST_MEMBERS, null, LINK_ID_USER_LIST_MEMBERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LIST_SUBSCRIBERS, null, LINK_ID_USER_LIST_SUBSCRIBERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LIST_MEMBERSHIPS, null, LINK_ID_USER_LIST_MEMBERSHIPS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_LISTS, null, LINK_ID_USER_LISTS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_GROUPS, null, LINK_ID_USER_GROUPS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_SAVED_SEARCHES, null, LINK_ID_SAVED_SEARCHES);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_MENTIONS, null, LINK_ID_USER_MENTIONS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_INCOMING_FRIENDSHIPS, null, LINK_ID_INCOMING_FRIENDSHIPS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_ITEMS, null, LINK_ID_ITEMS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_STATUS_RETWEETERS, null, LINK_ID_STATUS_RETWEETERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_STATUS_FAVORITERS, null, LINK_ID_STATUS_FAVORITERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_SEARCH, null, LINK_ID_SEARCH);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_MUTES_USERS, null, LINK_ID_MUTES_USERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_MAP, null, LINK_ID_MAP);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_SCHEDULED_STATUSES, null, LINK_ID_SCHEDULED_STATUSES);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_ACCOUNTS, null, LINK_ID_ACCOUNTS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_DRAFTS, null, LINK_ID_DRAFTS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_FILTERS, null, LINK_ID_FILTERS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_FILTERS, PATH_FILTERS_IMPORT_BLOCKS, LINK_ID_FILTERS_IMPORT_BLOCKS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_FILTERS, PATH_FILTERS_IMPORT_MUTES, LINK_ID_FILTERS_IMPORT_MUTES);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_FILTERS, PATH_FILTERS_SUBSCRIPTIONS, LINK_ID_FILTERS_SUBSCRIPTIONS);
LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_PROFILE_EDITOR, null, LINK_ID_PROFILE_EDITOR);
HOME_TABS_URI_MATCHER.addURI(CustomTabType.HOME_TIMELINE, null, TAB_CODE_HOME_TIMELINE); HOME_TABS_URI_MATCHER.addURI(CustomTabType.HOME_TIMELINE, null, TAB_CODE_HOME_TIMELINE);
HOME_TABS_URI_MATCHER.addURI(CustomTabType.NOTIFICATIONS_TIMELINE, null, TAB_CODE_NOTIFICATIONS_TIMELINE); HOME_TABS_URI_MATCHER.addURI(CustomTabType.NOTIFICATIONS_TIMELINE, null, TAB_CODE_NOTIFICATIONS_TIMELINE);
HOME_TABS_URI_MATCHER.addURI(CustomTabType.DIRECT_MESSAGES, null, TAB_CODE_DIRECT_MESSAGES); HOME_TABS_URI_MATCHER.addURI(CustomTabType.DIRECT_MESSAGES, null, TAB_CODE_DIRECT_MESSAGES);
@ -915,12 +874,6 @@ public final class Utils implements Constants {
} }
} }
public static int matchLinkId(@Nullable final Uri uri) {
if (uri == null) return UriMatcher.NO_MATCH;
return LINK_HANDLER_URI_MATCHER.match(uri);
}
public static int matchTabCode(@Nullable final Uri uri) { public static int matchTabCode(@Nullable final Uri uri) {
if (uri == null) return UriMatcher.NO_MATCH; if (uri == null) return UriMatcher.NO_MATCH;
return HOME_TABS_URI_MATCHER.match(uri); return HOME_TABS_URI_MATCHER.match(uri);

View File

@ -43,12 +43,8 @@ import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.iface.IControlBarActivity import org.mariotaku.twidere.activity.iface.IControlBarActivity
import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarShowHideHelper import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarShowHideHelper
import org.mariotaku.twidere.constant.CompatibilityConstants import org.mariotaku.twidere.constant.*
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_SIMPLE_LAYOUT import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER_KEY
import org.mariotaku.twidere.constant.KeyboardShortcutConstants
import org.mariotaku.twidere.constant.SharedPreferenceConstants
import org.mariotaku.twidere.constant.iWantMyStarsBackKey
import org.mariotaku.twidere.fragment.* import org.mariotaku.twidere.fragment.*
import org.mariotaku.twidere.fragment.filter.FiltersFragment import org.mariotaku.twidere.fragment.filter.FiltersFragment
import org.mariotaku.twidere.fragment.filter.FiltersImportBlocksFragment import org.mariotaku.twidere.fragment.filter.FiltersImportBlocksFragment
@ -64,7 +60,7 @@ import org.mariotaku.twidere.model.analyzer.PurchaseFinished
import org.mariotaku.twidere.util.* import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback
import org.mariotaku.twidere.util.Utils.LINK_ID_FILTERS_IMPORT_BLOCKS import org.mariotaku.twidere.util.Utils.LINK_ID_FILTERS_IMPORT_BLOCKS
import org.mariotaku.twidere.util.Utils.matchLinkId import org.mariotaku.twidere.util.linkhandler.TwidereLinkMatcher
class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IControlBarActivity, class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IControlBarActivity,
SupportFragmentCallback { SupportFragmentCallback {
@ -85,8 +81,11 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
controlBarShowHideHelper = ControlBarShowHideHelper(this) controlBarShowHideHelper = ControlBarShowHideHelper(this)
multiSelectHandler.dispatchOnCreate() multiSelectHandler.dispatchOnCreate()
val uri = intent.data val uri = intent.data ?: run {
val linkId = matchLinkId(uri) finish()
return
}
val linkId = TwidereLinkMatcher.match(uri)
intent.setExtrasClassLoader(classLoader) intent.setExtrasClassLoader(classLoader)
val fragment: Fragment val fragment: Fragment
try { try {
@ -413,6 +412,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
LINK_ID_FILTERS_IMPORT_MUTES -> { LINK_ID_FILTERS_IMPORT_MUTES -> {
title = getString(R.string.title_select_users) title = getString(R.string.title_select_users)
} }
LINK_ID_FILTERS_SUBSCRIPTIONS_ADD,
LINK_ID_FILTERS_SUBSCRIPTIONS -> { LINK_ID_FILTERS_SUBSCRIPTIONS -> {
title = getString(R.string.title_manage_filter_subscriptions) title = getString(R.string.title_manage_filter_subscriptions)
} }
@ -761,6 +761,15 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
fragment = FiltersSubscriptionsFragment() fragment = FiltersSubscriptionsFragment()
isAccountIdRequired = false isAccountIdRequired = false
} }
LINK_ID_FILTERS_SUBSCRIPTIONS_ADD -> {
val url = uri.getQueryParameter("url") ?: return null
val name = uri.getQueryParameter("name")
fragment = FiltersSubscriptionsFragment()
args.putString(IntentConstants.EXTRA_ACTION, FiltersSubscriptionsFragment.ACTION_ADD_URL_SUBSCRIPTION)
args.putString(FiltersSubscriptionsFragment.EXTRA_ADD_SUBSCRIPTION_URL, url)
args.putString(FiltersSubscriptionsFragment.EXTRA_ADD_SUBSCRIPTION_NAME, name)
isAccountIdRequired = false
}
else -> { else -> {
return null return null
} }

View File

@ -2,10 +2,10 @@ package org.mariotaku.twidere.activity
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.UriMatcher
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.util.Pair
import org.apache.commons.lang3.ArrayUtils import org.apache.commons.lang3.ArrayUtils
import org.mariotaku.ktextension.toLong import org.mariotaku.ktextension.toLong
import org.mariotaku.twidere.Constants import org.mariotaku.twidere.Constants
@ -17,35 +17,29 @@ import org.mariotaku.twidere.util.Analyzer
import org.mariotaku.twidere.util.IntentUtils import org.mariotaku.twidere.util.IntentUtils
import org.mariotaku.twidere.util.Utils import org.mariotaku.twidere.util.Utils
class WebLinkHandlerActivity : Activity(), Constants { class WebLinkHandlerActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val packageManager = packageManager val packageManager = packageManager
val intent = intent
intent.setExtrasClassLoader(TwidereApplication::class.java.classLoader) intent.setExtrasClassLoader(TwidereApplication::class.java.classLoader)
val uri = intent.data val uri = intent.data
if (uri == null || uri.host == null) { if (uri == null || uri.host == null) {
finish() finish()
return return
} }
val handled: Pair<Intent, Boolean>
when (uri.host) { val (handledIntent, handledSuccessfully) = when (uri.host) {
"twitter.com", "www.twitter.com", "mobile.twitter.com" -> { "twitter.com", "www.twitter.com", "mobile.twitter.com" -> handleTwitterLink(regulateTwitterUri(uri))
handled = handleTwitterLink(regulateTwitterUri(uri)) "fanfou.com" -> handleFanfouLink(uri)
} "twidere.mariotaku.org" -> handleTwidereExternalLink(uri)
"fanfou.com" -> { else -> Pair(null, false)
handled = handleFanfouLink(uri)
}
else -> {
handled = Pair.create<Intent, Boolean>(null, false)
}
} }
if (handled.first != null) { if (handledIntent != null) {
handled.first.putExtras(intent) handledIntent.putExtras(intent)
startActivity(handled.first) startActivity(handledIntent)
} else { } else {
if (!handled.second) { if (!handledSuccessfully) {
Analyzer.logException(TwitterLinkException("Unable to handle twitter uri " + uri)) Analyzer.logException(TwitterLinkException("Unable to handle twitter uri " + uri))
} }
val fallbackIntent = Intent(Intent.ACTION_VIEW, uri) val fallbackIntent = Intent(Intent.ACTION_VIEW, uri)
@ -70,7 +64,25 @@ class WebLinkHandlerActivity : Activity(), Constants {
setVisible(true) setVisible(true)
} }
private fun handleFanfouLink(uri: Uri): Pair<Intent, Boolean> { private fun handleTwidereExternalLink(uri: Uri): Pair<Intent?, Boolean> {
val pathSegments = uri.pathSegments
if (pathSegments.size < 2 || pathSegments[0] != "external") {
return Pair(null, false)
}
val builder = Uri.Builder()
builder.scheme(SCHEME_TWIDERE)
builder.authority(pathSegments[1])
if (pathSegments.size >= 3) {
for (segment in pathSegments.slice(2..pathSegments.lastIndex)) {
builder.appendPath(segment)
}
}
builder.encodedQuery(uri.encodedQuery)
builder.encodedFragment(uri.encodedFragment)
return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
}
private fun handleFanfouLink(uri: Uri): Pair<Intent?, Boolean> {
val pathSegments = uri.pathSegments val pathSegments = uri.pathSegments
if (pathSegments.size > 0) { if (pathSegments.size > 0) {
when (pathSegments[0]) { when (pathSegments[0]) {
@ -80,7 +92,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_STATUS) builder.authority(AUTHORITY_STATUS)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_FANFOU_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_FANFOU_COM)
builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, pathSegments[1]) builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, pathSegments[1])
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
else -> { else -> {
if (!ArrayUtils.contains(FANFOU_RESERVED_PATHS, pathSegments[0])) { if (!ArrayUtils.contains(FANFOU_RESERVED_PATHS, pathSegments[0])) {
@ -91,17 +103,17 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_FANFOU_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_FANFOU_COM)
val userKey = UserKey(pathSegments[0], USER_TYPE_FANFOU_COM) val userKey = UserKey(pathSegments[0], USER_TYPE_FANFOU_COM)
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, userKey.toString()) builder.appendQueryParameter(QUERY_PARAM_USER_KEY, userKey.toString())
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
} }
return Pair.create<Intent, Boolean>(null, false) return Pair(null, false)
} }
} }
} }
return Pair.create<Intent, Boolean>(null, false) return Pair(null, false)
} }
private fun handleTwitterLink(uri: Uri): Pair<Intent, Boolean> { private fun handleTwitterLink(uri: Uri): Pair<Intent?, Boolean> {
val pathSegments = uri.pathSegments val pathSegments = uri.pathSegments
if (pathSegments.size > 0) { if (pathSegments.size > 0) {
when (pathSegments[0]) { when (pathSegments[0]) {
@ -117,7 +129,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
val text = uri.getQueryParameter("text") val text = uri.getQueryParameter("text")
val url = uri.getQueryParameter("url") val url = uri.getQueryParameter("url")
handledIntent.putExtra(Intent.EXTRA_TEXT, Utils.getShareStatus(this, text, url)) handledIntent.putExtra(Intent.EXTRA_TEXT, Utils.getShareStatus(this, text, url))
return Pair.create(handledIntent, true) return Pair(handledIntent, true)
} }
"search" -> { "search" -> {
val builder = Uri.Builder() val builder = Uri.Builder()
@ -125,7 +137,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_SEARCH) builder.authority(AUTHORITY_SEARCH)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_QUERY, uri.getQueryParameter("q")) builder.appendQueryParameter(QUERY_PARAM_QUERY, uri.getQueryParameter("q"))
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
"hashtag" -> { "hashtag" -> {
val builder = Uri.Builder() val builder = Uri.Builder()
@ -133,41 +145,41 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_SEARCH) builder.authority(AUTHORITY_SEARCH)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_QUERY, "#${uri.lastPathSegment}") builder.appendQueryParameter(QUERY_PARAM_QUERY, "#${uri.lastPathSegment}")
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
"following" -> { "following" -> {
val builder = Uri.Builder() val builder = Uri.Builder()
builder.scheme(SCHEME_TWIDERE) builder.scheme(SCHEME_TWIDERE)
builder.authority(AUTHORITY_USER_FRIENDS) builder.authority(AUTHORITY_USER_FRIENDS)
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString()) builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString())
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
"followers" -> { "followers" -> {
val builder = Uri.Builder() val builder = Uri.Builder()
builder.scheme(SCHEME_TWIDERE) builder.scheme(SCHEME_TWIDERE)
builder.authority(AUTHORITY_USER_FOLLOWERS) builder.authority(AUTHORITY_USER_FOLLOWERS)
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString()) builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString())
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
"favorites" -> { "favorites" -> {
val builder = Uri.Builder() val builder = Uri.Builder()
builder.scheme(SCHEME_TWIDERE) builder.scheme(SCHEME_TWIDERE)
builder.authority(AUTHORITY_USER_FAVORITES) builder.authority(AUTHORITY_USER_FAVORITES)
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString()) builder.appendQueryParameter(QUERY_PARAM_USER_KEY, UserKey.SELF_REFERENCE.toString())
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
else -> { else -> {
if (ArrayUtils.contains(TWITTER_RESERVED_PATHS, pathSegments[0])) { if (ArrayUtils.contains(TWITTER_RESERVED_PATHS, pathSegments[0])) {
return Pair.create<Intent, Boolean>(null, true) return Pair(null, true)
} }
return handleUserSpecificPageIntent(uri, pathSegments, pathSegments[0]) return handleUserSpecificPageIntent(uri, pathSegments, pathSegments[0])
} }
} }
} }
return Pair.create<Intent, Boolean>(null, false) return Pair(null, false)
} }
private fun handleUserSpecificPageIntent(uri: Uri, pathSegments: List<String>, screenName: String): Pair<Intent, Boolean> { private fun handleUserSpecificPageIntent(uri: Uri, pathSegments: List<String>, screenName: String): Pair<Intent?, Boolean> {
val segsSize = pathSegments.size val segsSize = pathSegments.size
if (segsSize == 1) { if (segsSize == 1) {
val builder = Uri.Builder() val builder = Uri.Builder()
@ -175,7 +187,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_USER) builder.authority(AUTHORITY_USER)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName) builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} else if (segsSize == 2) { } else if (segsSize == 2) {
when (pathSegments[1]) { when (pathSegments[1]) {
"following" -> { "following" -> {
@ -184,7 +196,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_USER_FRIENDS) builder.authority(AUTHORITY_USER_FRIENDS)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName) builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
"followers" -> { "followers" -> {
val builder = Uri.Builder() val builder = Uri.Builder()
@ -192,7 +204,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_USER_FOLLOWERS) builder.authority(AUTHORITY_USER_FOLLOWERS)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName) builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
"favorites" -> { "favorites" -> {
val builder = Uri.Builder() val builder = Uri.Builder()
@ -200,7 +212,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_USER_FAVORITES) builder.authority(AUTHORITY_USER_FAVORITES)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName) builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
else -> { else -> {
val builder = Uri.Builder() val builder = Uri.Builder()
@ -209,7 +221,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName) builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments[1]) builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments[1])
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
} }
} else if (segsSize >= 3) { } else if (segsSize >= 3) {
@ -219,7 +231,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.authority(AUTHORITY_STATUS) builder.authority(AUTHORITY_STATUS)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, pathSegments[2]) builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, pathSegments[2])
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} else { } else {
when (pathSegments[2]) { when (pathSegments[2]) {
"members" -> { "members" -> {
@ -229,7 +241,7 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName) builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments[1]) builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments[1])
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
"subscribers" -> { "subscribers" -> {
val builder = Uri.Builder() val builder = Uri.Builder()
@ -238,16 +250,16 @@ class WebLinkHandlerActivity : Activity(), Constants {
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM) builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_HOST, USER_TYPE_TWITTER_COM)
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName) builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName)
builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments[1]) builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, pathSegments[1])
return Pair.create(Intent(Intent.ACTION_VIEW, builder.build()), true) return Pair(Intent(Intent.ACTION_VIEW, builder.build()), true)
} }
} }
} }
} }
return Pair.create<Intent, Boolean>(null, false) return Pair(null, false)
} }
private fun getTwitterIntentUriIntent(uri: Uri, pathSegments: List<String>): Pair<Intent, Boolean> { private fun getTwitterIntentUriIntent(uri: Uri, pathSegments: List<String>): Pair<Intent?, Boolean> {
if (pathSegments.size < 2) return Pair.create<Intent, Boolean>(null, false) if (pathSegments.size < 2) return Pair(null, false)
when (pathSegments[1]) { when (pathSegments[1]) {
"tweet" -> { "tweet" -> {
val handledIntent = Intent(this, ComposeActivity::class.java) val handledIntent = Intent(this, ComposeActivity::class.java)
@ -265,14 +277,14 @@ class WebLinkHandlerActivity : Activity(), Constants {
sb.append(url) sb.append(url)
} }
handledIntent.putExtra(Intent.EXTRA_TEXT, sb.toString()) handledIntent.putExtra(Intent.EXTRA_TEXT, sb.toString())
return Pair.create(handledIntent, true) return Pair(handledIntent, true)
} }
} }
return Pair.create<Intent, Boolean>(null, false) return Pair(null, false)
} }
private fun getIUriIntent(uri: Uri, pathSegments: List<String>): Pair<Intent, Boolean> { private fun getIUriIntent(uri: Uri, pathSegments: List<String>): Pair<Intent?, Boolean> {
return Pair.create<Intent, Boolean>(null, false) return Pair(null, false)
} }
private inner class TwitterLinkException(s: String) : Exception(s) private inner class TwitterLinkException(s: String) : Exception(s)

View File

@ -1,6 +1,9 @@
package org.mariotaku.twidere.fragment package org.mariotaku.twidere.fragment
import android.app.Activity
import android.app.Dialog import android.app.Dialog
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.FragmentManager import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
@ -43,12 +46,12 @@ class ExtraFeaturesIntroductionDialogFragment : BaseDialogFragment() {
Analyzer.log(PurchaseConfirm(PurchaseFinished.NAME_EXTRA_FEATURES)) Analyzer.log(PurchaseConfirm(PurchaseFinished.NAME_EXTRA_FEATURES))
} }
builder.setNegativeButton(R.string.action_later) { dialog, which -> builder.setNegativeButton(R.string.action_later) { dialog, which ->
onDialogCancelled()
} }
val restorePurchaseIntent = extraFeaturesService.createRestorePurchaseIntent(context, feature) val restorePurchaseIntent = extraFeaturesService.createRestorePurchaseIntent(context, feature)
if (restorePurchaseIntent != null) { if (restorePurchaseIntent != null) {
builder.setNeutralButton(R.string.action_restore_purchase) { dialog, which -> builder.setNeutralButton(R.string.action_restore_purchase) { dialog, which ->
startActivity(restorePurchaseIntent) startActivityForResultOnTarget(restorePurchaseIntent)
} }
} }
val dialog = builder.create() val dialog = builder.create()
@ -75,14 +78,30 @@ class ExtraFeaturesIntroductionDialogFragment : BaseDialogFragment() {
return dialog return dialog
} }
override fun onCancel(dialog: DialogInterface?) {
onDialogCancelled()
}
private fun onDialogCancelled() {
if (targetRequestCode != 0) {
targetFragment?.onActivityResult(targetRequestCode, Activity.RESULT_CANCELED, null)
}
}
private fun startPurchase(feature: String) { private fun startPurchase(feature: String) {
val purchaseIntent = extraFeaturesService.createPurchaseIntent(context, feature) val purchaseIntent = extraFeaturesService.createPurchaseIntent(context, feature) ?: return
if (requestCode == 0) { startActivityForResultOnTarget(purchaseIntent)
startActivity(purchaseIntent) }
private fun startActivityForResultOnTarget(intent: Intent) {
if (targetFragment != null) {
targetFragment.startActivityForResult(intent, targetRequestCode)
} else if (requestCode == 0) {
startActivity(intent)
} else if (parentFragment != null) { } else if (parentFragment != null) {
parentFragment.startActivityForResult(purchaseIntent, requestCode) parentFragment.startActivityForResult(intent, requestCode)
} else { } else {
activity.startActivityForResult(purchaseIntent, requestCode) activity.startActivityForResult(intent, requestCode)
} }
} }

View File

@ -1,10 +1,13 @@
package org.mariotaku.twidere.fragment.filter package org.mariotaku.twidere.fragment.filter
import android.app.Activity
import android.app.Dialog import android.app.Dialog
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent
import android.database.Cursor import android.database.Cursor
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.DialogFragment
import android.support.v4.app.LoaderManager import android.support.v4.app.LoaderManager
import android.support.v4.content.CursorLoader import android.support.v4.content.CursorLoader
import android.support.v4.content.Loader import android.support.v4.content.Loader
@ -16,19 +19,28 @@ import com.rengwuxian.materialedittext.MaterialEditText
import kotlinx.android.synthetic.main.layout_list_with_empty_view.* import kotlinx.android.synthetic.main.layout_list_with_empty_view.*
import okhttp3.HttpUrl import okhttp3.HttpUrl
import org.mariotaku.abstask.library.TaskStarter import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.empty import org.mariotaku.ktextension.empty
import org.mariotaku.ktextension.isEmpty import org.mariotaku.ktextension.isEmpty
import org.mariotaku.ktextension.set
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.REQUEST_PURCHASE_EXTRA_FEATURES
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACTION
import org.mariotaku.twidere.constant.IntentConstants.INTENT_PACKAGE_PREFIX
import org.mariotaku.twidere.extension.model.getComponentLabel import org.mariotaku.twidere.extension.model.getComponentLabel
import org.mariotaku.twidere.extension.model.setupUrl import org.mariotaku.twidere.extension.model.setupUrl
import org.mariotaku.twidere.fragment.BaseDialogFragment import org.mariotaku.twidere.fragment.BaseDialogFragment
import org.mariotaku.twidere.fragment.BaseFragment import org.mariotaku.twidere.fragment.BaseFragment
import org.mariotaku.twidere.fragment.ExtraFeaturesIntroductionDialogFragment
import org.mariotaku.twidere.fragment.ProgressDialogFragment import org.mariotaku.twidere.fragment.ProgressDialogFragment
import org.mariotaku.twidere.model.FiltersSubscription import org.mariotaku.twidere.model.FiltersSubscription
import org.mariotaku.twidere.model.FiltersSubscriptionCursorIndices import org.mariotaku.twidere.model.FiltersSubscriptionCursorIndices
import org.mariotaku.twidere.model.FiltersSubscriptionValuesCreator import org.mariotaku.twidere.model.FiltersSubscriptionValuesCreator
import org.mariotaku.twidere.model.analyzer.PurchaseFinished
import org.mariotaku.twidere.provider.TwidereDataStore.Filters import org.mariotaku.twidere.provider.TwidereDataStore.Filters
import org.mariotaku.twidere.task.filter.RefreshFiltersSubscriptionsTask import org.mariotaku.twidere.task.filter.RefreshFiltersSubscriptionsTask
import org.mariotaku.twidere.util.Analyzer
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
import org.mariotaku.twidere.util.view.SimpleTextWatcher import org.mariotaku.twidere.util.view.SimpleTextWatcher
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ -49,6 +61,53 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
listContainer.visibility = View.GONE listContainer.visibility = View.GONE
progressContainer.visibility = View.VISIBLE progressContainer.visibility = View.VISIBLE
loaderManager.initLoader(0, null, this) loaderManager.initLoader(0, null, this)
if (!extraFeaturesService.isSupported()) {
activity?.finish()
return
}
if (savedInstanceState == null) {
when (arguments?.getString(EXTRA_ACTION)) {
ACTION_ADD_URL_SUBSCRIPTION -> {
if (extraFeaturesService.isEnabled(ExtraFeaturesService.FEATURE_FILTERS_SUBSCRIPTION).not()) {
val df = ExtraFeaturesIntroductionDialogFragment.show(childFragmentManager,
ExtraFeaturesService.FEATURE_FILTERS_SUBSCRIPTION)
df.setTargetFragment(this, REQUEST_ADD_URL_SUBSCRIPTION_PURCHASE)
} else {
showAddUrlSubscription()
}
}
else -> {
val df = ExtraFeaturesIntroductionDialogFragment.show(childFragmentManager,
ExtraFeaturesService.FEATURE_FILTERS_SUBSCRIPTION)
df.setTargetFragment(this, REQUEST_PURCHASE_EXTRA_FEATURES)
}
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_ADD_URL_SUBSCRIPTION_PURCHASE -> {
if (resultCode == Activity.RESULT_OK) {
Analyzer.log(PurchaseFinished.create(data!!))
executeAfterFragmentResumed { fragment ->
(fragment as FiltersSubscriptionsFragment).showAddUrlSubscription()
}
} else {
activity?.finish()
}
}
REQUEST_PURCHASE_EXTRA_FEATURES -> {
if (resultCode == Activity.RESULT_OK) {
Analyzer.log(PurchaseFinished.create(data!!))
} else {
activity?.finish()
}
}
}
} }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -63,12 +122,18 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
return true return true
} }
R.id.refresh -> { R.id.refresh -> {
val dfRef = WeakReference(ProgressDialogFragment.show(childFragmentManager, "refresh_filters")) executeAfterFragmentResumed { fragment ->
val task = RefreshFiltersSubscriptionsTask(context) val dfRef = WeakReference(ProgressDialogFragment.show(fragment.childFragmentManager, "refresh_filters"))
task.callback = { val task = RefreshFiltersSubscriptionsTask(fragment.context)
dfRef.get()?.dismiss() val fragmentRef = WeakReference(fragment)
task.callback = {
fragmentRef.get()?.executeAfterFragmentResumed { fragment ->
val df = dfRef.get() ?: fragment.childFragmentManager.findFragmentByTag("refresh_filters") as? DialogFragment
df?.dismiss()
}
}
TaskStarter.execute(task)
} }
TaskStarter.execute(task)
return true return true
} }
else -> return false else -> return false
@ -105,6 +170,15 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
progressContainer.visibility = View.GONE progressContainer.visibility = View.GONE
} }
private fun showAddUrlSubscription() {
val df = AddUrlSubscriptionDialogFragment()
df.arguments = Bundle {
this[EXTRA_ADD_SUBSCRIPTION_URL] = arguments?.getString(EXTRA_ADD_SUBSCRIPTION_URL)
this[EXTRA_ADD_SUBSCRIPTION_NAME] = arguments?.getString(EXTRA_ADD_SUBSCRIPTION_NAME)
}
df.show(fragmentManager, "add_url_subscription")
}
class FilterSubscriptionsAdapter(context: Context) : SimpleCursorAdapter(context, class FilterSubscriptionsAdapter(context: Context) : SimpleCursorAdapter(context,
R.layout.list_item_two_line, null, arrayOf(Filters.Subscriptions.NAME), R.layout.list_item_two_line, null, arrayOf(Filters.Subscriptions.NAME),
intArrayOf(android.R.id.text1), 0) { intArrayOf(android.R.id.text1), 0) {
@ -163,11 +237,25 @@ class FiltersSubscriptionsFragment : BaseFragment(), LoaderManager.LoaderCallbac
} }
editName.addTextChangedListener(watcher) editName.addTextChangedListener(watcher)
editUrl.addTextChangedListener(watcher) editUrl.addTextChangedListener(watcher)
val args = arguments
if (savedInstanceState == null && args != null) {
editName.setText(args.getString(EXTRA_ADD_SUBSCRIPTION_NAME))
editUrl.setText(args.getString(EXTRA_ADD_SUBSCRIPTION_URL))
}
updateEnableState() updateEnableState()
} }
return dialog return dialog
} }
} }
companion object {
const val ACTION_ADD_URL_SUBSCRIPTION = "${INTENT_PACKAGE_PREFIX}ADD_URL_FILTERS_SUBSCRIPTION"
const val REQUEST_ADD_URL_SUBSCRIPTION_PURCHASE = 101
const val EXTRA_ADD_SUBSCRIPTION_URL = "add_subscription.url"
const val EXTRA_ADD_SUBSCRIPTION_NAME = "add_subscription.name"
}
} }

View File

@ -155,6 +155,7 @@ object ParcelableStatusUtils {
result.spans = textWithIndices.spans result.spans = textWithIndices.spans
result.extras.display_text_range = textWithIndices.range result.extras.display_text_range = textWithIndices.range
} }
result.media = ParcelableMediaUtils.fromStatus(status) result.media = ParcelableMediaUtils.fromStatus(status)
result.source = status.source result.source = status.source
result.location = getLocation(status) result.location = getLocation(status)
@ -191,10 +192,6 @@ object ParcelableStatusUtils {
return text.contains("<") && text.contains(">") return text.contains("<") && text.contains(">")
} }
private fun isFanfouStatus(accountKey: UserKey): Boolean {
return USER_TYPE_FANFOU_COM == accountKey.host
}
private fun getInReplyToUserId(status: Status, accountKey: UserKey): UserKey? { private fun getInReplyToUserId(status: Status, accountKey: UserKey): UserKey? {
val inReplyToUserId = status.inReplyToUserId ?: return null val inReplyToUserId = status.inReplyToUserId ?: return null
val entities = status.userMentionEntities val entities = status.userMentionEntities

View File

@ -0,0 +1,58 @@
package org.mariotaku.twidere.util.linkhandler
import android.content.UriMatcher
import android.net.Uri
import org.mariotaku.twidere.Constants.*
/**
* Created by Mariotaku on 2017/1/18.
*/
object TwidereLinkMatcher {
private val matcher = UriMatcher(UriMatcher.NO_MATCH).apply {
addURI(AUTHORITY_STATUS, null, LINK_ID_STATUS)
addURI(AUTHORITY_USER, null, LINK_ID_USER)
addURI(AUTHORITY_USER_TIMELINE, null, LINK_ID_USER_TIMELINE)
addURI(AUTHORITY_USER_MEDIA_TIMELINE, null, LINK_ID_USER_MEDIA_TIMELINE)
addURI(AUTHORITY_USER_FOLLOWERS, null, LINK_ID_USER_FOLLOWERS)
addURI(AUTHORITY_USER_FRIENDS, null, LINK_ID_USER_FRIENDS)
addURI(AUTHORITY_USER_FAVORITES, null, LINK_ID_USER_FAVORITES)
addURI(AUTHORITY_USER_BLOCKS, null, LINK_ID_USER_BLOCKS)
addURI(AUTHORITY_DIRECT_MESSAGES_CONVERSATION, null,
LINK_ID_DIRECT_MESSAGES_CONVERSATION)
addURI(AUTHORITY_DIRECT_MESSAGES, null, LINK_ID_DIRECT_MESSAGES)
addURI(AUTHORITY_INTERACTIONS, null, LINK_ID_INTERACTIONS)
addURI(AUTHORITY_PUBLIC_TIMELINE, null, LINK_ID_PUBLIC_TIMELINE)
addURI(AUTHORITY_USER_LIST, null, LINK_ID_USER_LIST)
addURI(AUTHORITY_GROUP, null, LINK_ID_GROUP)
addURI(AUTHORITY_USER_LIST_TIMELINE, null, LINK_ID_USER_LIST_TIMELINE)
addURI(AUTHORITY_USER_LIST_MEMBERS, null, LINK_ID_USER_LIST_MEMBERS)
addURI(AUTHORITY_USER_LIST_SUBSCRIBERS, null, LINK_ID_USER_LIST_SUBSCRIBERS)
addURI(AUTHORITY_USER_LIST_MEMBERSHIPS, null, LINK_ID_USER_LIST_MEMBERSHIPS)
addURI(AUTHORITY_USER_LISTS, null, LINK_ID_USER_LISTS)
addURI(AUTHORITY_USER_GROUPS, null, LINK_ID_USER_GROUPS)
addURI(AUTHORITY_SAVED_SEARCHES, null, LINK_ID_SAVED_SEARCHES)
addURI(AUTHORITY_USER_MENTIONS, null, LINK_ID_USER_MENTIONS)
addURI(AUTHORITY_INCOMING_FRIENDSHIPS, null, LINK_ID_INCOMING_FRIENDSHIPS)
addURI(AUTHORITY_ITEMS, null, LINK_ID_ITEMS)
addURI(AUTHORITY_STATUS_RETWEETERS, null, LINK_ID_STATUS_RETWEETERS)
addURI(AUTHORITY_STATUS_FAVORITERS, null, LINK_ID_STATUS_FAVORITERS)
addURI(AUTHORITY_SEARCH, null, LINK_ID_SEARCH)
addURI(AUTHORITY_MUTES_USERS, null, LINK_ID_MUTES_USERS)
addURI(AUTHORITY_MAP, null, LINK_ID_MAP)
addURI(AUTHORITY_SCHEDULED_STATUSES, null, LINK_ID_SCHEDULED_STATUSES)
addURI(AUTHORITY_ACCOUNTS, null, LINK_ID_ACCOUNTS)
addURI(AUTHORITY_DRAFTS, null, LINK_ID_DRAFTS)
addURI(AUTHORITY_FILTERS, null, LINK_ID_FILTERS)
addURI(AUTHORITY_FILTERS, PATH_FILTERS_IMPORT_BLOCKS, LINK_ID_FILTERS_IMPORT_BLOCKS)
addURI(AUTHORITY_FILTERS, PATH_FILTERS_IMPORT_MUTES, LINK_ID_FILTERS_IMPORT_MUTES)
addURI(AUTHORITY_FILTERS, PATH_FILTERS_SUBSCRIPTIONS, LINK_ID_FILTERS_SUBSCRIPTIONS)
addURI(AUTHORITY_FILTERS, PATH_FILTERS_SUBSCRIPTIONS_ADD, LINK_ID_FILTERS_SUBSCRIPTIONS_ADD)
addURI(AUTHORITY_PROFILE_EDITOR, null, LINK_ID_PROFILE_EDITOR)
}
fun match(uri: Uri): Int {
return matcher.match(uri)
}
}